viem_rb 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/lib/viem/actions/public/get_logs.rb +109 -11
- data/lib/viem/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b484347f34f49daa07a62c0de9470faefab1b9ea6eb95573fc92b8785fc2e228
|
|
4
|
+
data.tar.gz: 431aadd5602eebd269ebea09884d1614355b57c3979e5e301c1dbd0451d60bf3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1e6e9137eee7e6840dd5fd62702d7689d2f8dde28e74338e0cc4fbcfa5ab160633d64d616e8c992e3111b8a401424d3762753f72d24494b2adc4402af7805514
|
|
7
|
+
data.tar.gz: 62a543abdc1014f1e750a2ec7158a90ebc9dea761cabe06a99da25d6efacc2ae4cb83fe2f33c0e1d3369ae5532736d7c88c28a4732db7228e7d92ed2d2a3a76f
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.1.3] - 2026-03-19
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- `get_logs` fully completed:
|
|
12
|
+
- `block_hash:` param — filter logs from a specific block hash (mutually exclusive with `from_block`/`to_block`)
|
|
13
|
+
- Multi-address support — `address:` now accepts an array of contract addresses
|
|
14
|
+
- Address validation on `address:` param (raises `InvalidAddressError` for invalid inputs)
|
|
15
|
+
- Full indexed args encoding — `args:` hash now encodes topic1/2/3 by type (`address`, `bool`, `uint`, `int`, `bytes32`, `bytes`, `string`)
|
|
16
|
+
- OR filtering — pass an array as an arg value to generate a multi-value OR topic filter
|
|
17
|
+
- Raw `topics:` override — bypass event/args encoding and pass topics directly
|
|
18
|
+
- Tuple event support — canonical type resolution for events with `tuple` inputs
|
|
19
|
+
- Trailing nil wildcard stripping — topics array is trimmed to the last meaningful filter
|
|
20
|
+
- 31 new specs for `get_logs` (192 total, 0 failures)
|
|
21
|
+
|
|
8
22
|
## [0.1.2] - 2026-03-19
|
|
9
23
|
|
|
10
24
|
### Fixed
|
|
@@ -4,29 +4,127 @@ module Viem
|
|
|
4
4
|
module Actions
|
|
5
5
|
module Public
|
|
6
6
|
module GetLogs
|
|
7
|
-
|
|
7
|
+
# Fetch event logs from the chain.
|
|
8
|
+
#
|
|
9
|
+
# @param address [String, Array<String>, nil] Contract address(es) to filter
|
|
10
|
+
# @param event [Hash, nil] ABI item for the event (generates topic0)
|
|
11
|
+
# @param args [Hash] Indexed argument values to filter (topic1+).
|
|
12
|
+
# Values can be arrays for OR filtering.
|
|
13
|
+
# @param from_block [Integer, String, nil] Start block (number, "latest", "earliest", "pending")
|
|
14
|
+
# @param to_block [Integer, String, nil] End block
|
|
15
|
+
# @param block_hash [String, nil] Filter by specific block hash (exclusive with from/to)
|
|
16
|
+
# @param topics [Array, nil] Raw topics override (skips event+args encoding)
|
|
17
|
+
#
|
|
18
|
+
# @return [Array<Hash>] Formatted log objects
|
|
19
|
+
def get_logs(
|
|
20
|
+
address: nil,
|
|
21
|
+
event: nil,
|
|
22
|
+
args: {},
|
|
23
|
+
from_block: nil,
|
|
24
|
+
to_block: nil,
|
|
25
|
+
block_hash: nil,
|
|
26
|
+
topics: nil
|
|
27
|
+
)
|
|
28
|
+
raise ArgumentError, "block_hash is mutually exclusive with from_block/to_block" \
|
|
29
|
+
if block_hash && (from_block || to_block)
|
|
30
|
+
|
|
8
31
|
params = {}
|
|
9
|
-
|
|
10
|
-
params[:
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
32
|
+
|
|
33
|
+
params[:address] = encode_address_filter(address) if address
|
|
34
|
+
|
|
35
|
+
if block_hash
|
|
36
|
+
params[:blockHash] = block_hash
|
|
37
|
+
else
|
|
38
|
+
params[:fromBlock] = encode_block_param(from_block) if from_block
|
|
39
|
+
params[:toBlock] = encode_block_param(to_block) if to_block
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
encoded_topics = topics || (event ? encode_event_topics(event, args) : nil)
|
|
43
|
+
params[:topics] = encoded_topics if encoded_topics
|
|
44
|
+
|
|
14
45
|
results = @transport.request("eth_getLogs", [stringify_keys(params)])
|
|
15
46
|
results.map { |l| format_log(l) }
|
|
16
47
|
end
|
|
17
48
|
|
|
18
49
|
private
|
|
19
50
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
51
|
+
# Encode address or array of addresses, validating each one.
|
|
52
|
+
def encode_address_filter(address)
|
|
53
|
+
if address.is_a?(Array)
|
|
54
|
+
address.map { |a| Utils::Address.get_address(a) }
|
|
55
|
+
else
|
|
56
|
+
Utils::Address.get_address(address)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Convert block param to hex string or pass through string tags.
|
|
61
|
+
def encode_block_param(value)
|
|
62
|
+
return value if value.is_a?(String)
|
|
63
|
+
|
|
64
|
+
Utils::Hex.number_to_hex(value)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Build topics array from event ABI + args.
|
|
68
|
+
# topic0 = keccak256(event signature)
|
|
69
|
+
# topic1+ = encoded indexed argument values (nil = wildcard)
|
|
70
|
+
def encode_event_topics(event_abi, args)
|
|
71
|
+
topic0 = Utils::Hash.keccak256(event_signature(event_abi))
|
|
72
|
+
topics = [topic0]
|
|
73
|
+
|
|
74
|
+
indexed_inputs = (event_abi["inputs"] || []).select { |i| i["indexed"] }
|
|
75
|
+
indexed_inputs.each do |input|
|
|
76
|
+
name = input["name"]
|
|
77
|
+
value = if args.is_a?(Hash)
|
|
78
|
+
args.key?(name) ? args[name] : args[name.to_sym]
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
topics << if value.nil?
|
|
82
|
+
nil # wildcard — match any value for this topic position
|
|
83
|
+
elsif value.is_a?(Array)
|
|
84
|
+
value.map { |v| encode_topic_value(input["type"], v) }
|
|
85
|
+
else
|
|
86
|
+
encode_topic_value(input["type"], value)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Strip trailing wildcards to keep the request minimal
|
|
91
|
+
topics.reverse.drop_while(&:nil?).reverse
|
|
24
92
|
end
|
|
25
93
|
|
|
94
|
+
# ABI-encode a single indexed value to a 32-byte hex topic.
|
|
95
|
+
def encode_topic_value(type, value)
|
|
96
|
+
case type
|
|
97
|
+
when "address"
|
|
98
|
+
addr = Utils::Address.get_address(value).delete_prefix("0x").downcase
|
|
99
|
+
"0x#{"0" * 24}#{addr}"
|
|
100
|
+
when "bool"
|
|
101
|
+
value ? "0x#{"0" * 63}1" : "0x#{"0" * 64}"
|
|
102
|
+
when /\Auint\d*\z/, /\Aint\d*\z/
|
|
103
|
+
Abi::Encoder.encode_abi_parameters([type], [value])
|
|
104
|
+
when /\Abytes(\d+)\z/
|
|
105
|
+
raw = value.delete_prefix("0x")
|
|
106
|
+
"0x#{raw.ljust(64, "0")}"
|
|
107
|
+
when "bytes", "string"
|
|
108
|
+
# Dynamic types are stored as keccak256 of their content
|
|
109
|
+
Utils::Hash.keccak256(value)
|
|
110
|
+
else
|
|
111
|
+
value
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Build canonical event signature string for keccak256 hashing.
|
|
26
116
|
def event_signature(abi_item)
|
|
27
|
-
inputs = (abi_item["inputs"] || []).map { |i| i
|
|
117
|
+
inputs = (abi_item["inputs"] || []).map { |i| canonical_type(i) }.join(",")
|
|
28
118
|
"#{abi_item["name"]}(#{inputs})"
|
|
29
119
|
end
|
|
120
|
+
|
|
121
|
+
# Resolve tuple types to their canonical form for signature hashing.
|
|
122
|
+
def canonical_type(input)
|
|
123
|
+
return input["type"] unless input["type"] == "tuple"
|
|
124
|
+
|
|
125
|
+
inner = (input["components"] || []).map { |c| canonical_type(c) }.join(",")
|
|
126
|
+
"(#{inner})"
|
|
127
|
+
end
|
|
30
128
|
end
|
|
31
129
|
end
|
|
32
130
|
end
|
data/lib/viem/version.rb
CHANGED