eth 0.5.13 → 0.5.15
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/.github/workflows/codeql.yml +1 -1
- data/.github/workflows/docs.yml +2 -2
- data/.github/workflows/spec.yml +1 -3
- data/CHANGELOG.md +33 -0
- data/CODE_OF_CONDUCT.md +3 -5
- data/Gemfile +3 -3
- data/LICENSE.txt +1 -1
- data/README.md +6 -6
- data/SECURITY.md +2 -2
- data/eth.gemspec +4 -1
- data/lib/eth/abi/decoder.rb +18 -7
- data/lib/eth/abi/encoder.rb +14 -26
- data/lib/eth/abi/event.rb +5 -1
- data/lib/eth/abi/function.rb +124 -0
- data/lib/eth/abi/packed/encoder.rb +196 -0
- data/lib/eth/abi/type.rb +77 -16
- data/lib/eth/abi.rb +29 -2
- data/lib/eth/address.rb +3 -1
- data/lib/eth/api.rb +1 -1
- data/lib/eth/chain.rb +9 -1
- data/lib/eth/client/http.rb +7 -3
- data/lib/eth/client/ipc.rb +1 -1
- data/lib/eth/client.rb +38 -37
- data/lib/eth/constant.rb +1 -1
- data/lib/eth/contract/error.rb +62 -0
- data/lib/eth/contract/event.rb +69 -16
- data/lib/eth/contract/function.rb +22 -1
- data/lib/eth/contract/function_input.rb +1 -1
- data/lib/eth/contract/function_output.rb +12 -4
- data/lib/eth/contract/initializer.rb +1 -1
- data/lib/eth/contract.rb +56 -5
- data/lib/eth/eip712.rb +49 -13
- data/lib/eth/ens/coin_type.rb +1 -1
- data/lib/eth/ens/resolver.rb +1 -1
- data/lib/eth/ens.rb +1 -1
- data/lib/eth/key/decrypter.rb +1 -1
- data/lib/eth/key/encrypter.rb +1 -1
- data/lib/eth/key.rb +2 -2
- data/lib/eth/rlp/decoder.rb +1 -1
- data/lib/eth/rlp/encoder.rb +1 -1
- data/lib/eth/rlp/sedes/big_endian_int.rb +1 -1
- data/lib/eth/rlp/sedes/binary.rb +1 -1
- data/lib/eth/rlp/sedes/list.rb +1 -1
- data/lib/eth/rlp/sedes.rb +1 -1
- data/lib/eth/rlp.rb +1 -1
- data/lib/eth/signature.rb +1 -1
- data/lib/eth/solidity.rb +1 -1
- data/lib/eth/tx/eip1559.rb +33 -8
- data/lib/eth/tx/eip2930.rb +32 -7
- data/lib/eth/tx/eip4844.rb +389 -0
- data/lib/eth/tx/eip7702.rb +520 -0
- data/lib/eth/tx/legacy.rb +31 -7
- data/lib/eth/tx.rb +88 -1
- data/lib/eth/unit.rb +1 -1
- data/lib/eth/util.rb +20 -8
- data/lib/eth/version.rb +2 -2
- data/lib/eth.rb +1 -1
- metadata +26 -16
data/lib/eth/contract/event.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2016-
|
1
|
+
# Copyright (c) 2016-2025 The Ruby-Eth Contributors
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -16,40 +16,93 @@
|
|
16
16
|
|
17
17
|
# Provides the {Eth} module.
|
18
18
|
module Eth
|
19
|
-
|
20
19
|
# Provide classes for contract event.
|
21
20
|
class Contract::Event
|
22
|
-
attr_accessor :name, :signature, :input_types, :inputs, :event_string, :address
|
23
|
-
|
24
21
|
# Constructor of the {Eth::Contract::Event} class.
|
25
22
|
#
|
26
23
|
# @param data [Hash] contract event data.
|
27
24
|
def initialize(data)
|
28
|
-
@
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
25
|
+
@data = data
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns the name of the event.
|
29
|
+
#
|
30
|
+
# @return [String] The event name.
|
31
|
+
def name
|
32
|
+
@data["name"]
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns the input types for the event.
|
36
|
+
#
|
37
|
+
# @return [Array<String>] An array of input type names.
|
38
|
+
def input_types
|
39
|
+
@input_types ||= @data["inputs"].map { |x| type_name(x) }
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns the names of input parameters.
|
43
|
+
#
|
44
|
+
# @return [Array<String>] An array of input parameter names.
|
45
|
+
def inputs
|
46
|
+
@inputs ||= @data["inputs"].map { |x| x["name"] }
|
47
|
+
end
|
48
|
+
|
49
|
+
# Returns the event signature string.
|
50
|
+
#
|
51
|
+
# @return [String] The event signature string, generated from ABI.
|
52
|
+
def event_string
|
53
|
+
@event_string ||= Abi::Event.signature(@data)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns the Keccak-256 event signature hash.
|
57
|
+
#
|
58
|
+
# @return [String] The event signature hash in hexadecimal format.
|
59
|
+
def signature
|
60
|
+
@signature ||= Digest::Keccak.hexdigest(event_string, 256)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns the Ethereum address associated with the event.
|
64
|
+
#
|
65
|
+
# @return [String, nil] The Ethereum address, or `nil` if not set.
|
66
|
+
def address
|
67
|
+
@address ||= nil
|
35
68
|
end
|
36
69
|
|
37
70
|
# Set the address of the smart contract
|
38
71
|
#
|
39
72
|
# @param address [String] contract address.
|
40
73
|
def set_address(address)
|
41
|
-
@address = address
|
74
|
+
@address = address ? Eth::Address.new(address).address : nil
|
75
|
+
end
|
76
|
+
|
77
|
+
# Decodes event parameters from logs.
|
78
|
+
#
|
79
|
+
# @param topics [Array<String>] The list of log topics, including the event selector.
|
80
|
+
# @param data [String] The log data containing non-indexed parameters.
|
81
|
+
# @return [ActiveSupport::HashWithIndifferentAccess] A hash of decoded event parameters.
|
82
|
+
def decode_params(topics, data = "0x")
|
83
|
+
inputs = @data["inputs"]
|
84
|
+
|
85
|
+
indexed_inputs, non_indexed_inputs = inputs.partition { _1["indexed"] }
|
86
|
+
|
87
|
+
{
|
88
|
+
**indexed_inputs.each_with_index.inject({}) do |result, (input, index)|
|
89
|
+
result[input["name"]] = Eth::Abi.decode([input["type"]], topics[index + 1])[0]
|
90
|
+
result
|
91
|
+
end,
|
92
|
+
**Hash[non_indexed_inputs.map { _1["name"] }.zip(
|
93
|
+
Eth::Abi.decode(non_indexed_inputs.map { |i| i["type"] }, data)
|
94
|
+
)],
|
95
|
+
}
|
42
96
|
end
|
43
97
|
|
44
98
|
private
|
45
99
|
|
46
100
|
def type_name(x)
|
47
|
-
|
48
|
-
case type
|
101
|
+
case x["type"]
|
49
102
|
when "tuple"
|
50
|
-
"(#{x["components"].
|
103
|
+
"(#{x["components"].map { |c| type_name(c) }.join(",")})"
|
51
104
|
else
|
52
|
-
type
|
105
|
+
x["type"]
|
53
106
|
end
|
54
107
|
end
|
55
108
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2016-
|
1
|
+
# Copyright (c) 2016-2025 The Ruby-Eth Contributors
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -53,5 +53,26 @@ module Eth
|
|
53
53
|
def self.encoded_function_signature(signature)
|
54
54
|
Util.bin_to_hex Util.keccak256(signature)[0..3]
|
55
55
|
end
|
56
|
+
|
57
|
+
# Encodes a function call arguments
|
58
|
+
#
|
59
|
+
# @param args [Array] function arguments
|
60
|
+
# @return [String] encoded function call data
|
61
|
+
def encode_call(*args)
|
62
|
+
types = inputs.map(&:parsed_type)
|
63
|
+
encoded_str = Util.bin_to_hex(Eth::Abi.encode(types, args))
|
64
|
+
Util.prefix_hex(signature + (encoded_str.empty? ? "0" * 64 : encoded_str))
|
65
|
+
end
|
66
|
+
|
67
|
+
# Decodes a function call result
|
68
|
+
#
|
69
|
+
# @param data [String] eth_call result in hex format
|
70
|
+
# @return [Array]
|
71
|
+
def decode_call_result(data)
|
72
|
+
return nil if data == "0x"
|
73
|
+
|
74
|
+
types = outputs.map(&:parsed_type)
|
75
|
+
Eth::Abi.decode(types, data)
|
76
|
+
end
|
56
77
|
end
|
57
78
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2016-
|
1
|
+
# Copyright (c) 2016-2025 The Ruby-Eth Contributors
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -19,19 +19,27 @@ module Eth
|
|
19
19
|
|
20
20
|
# Provide classes for contract function output.
|
21
21
|
class Contract::FunctionOutput
|
22
|
-
attr_accessor :type, :name
|
22
|
+
attr_accessor :type, :raw_type, :name
|
23
23
|
|
24
24
|
# Constructor of the {Eth::Contract::FunctionOutput} class.
|
25
25
|
#
|
26
26
|
# @param data [Hash] contract abi data.
|
27
27
|
def initialize(data)
|
28
|
-
@
|
28
|
+
@raw_type = data["type"]
|
29
|
+
@type = Eth::Abi::Type.parse(data["type"], data["components"])
|
29
30
|
@name = data["name"]
|
30
31
|
end
|
31
32
|
|
32
33
|
# Returns complete types with subtypes, e.g., `uint256`.
|
33
34
|
def type
|
34
|
-
@type.base_type +
|
35
|
+
@type.base_type +
|
36
|
+
@type.sub_type +
|
37
|
+
@type.dimensions.map { |dimension| "[#{dimension > 0 ? dimension : ""}]" }.join("")
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns parsed types.
|
41
|
+
def parsed_type
|
42
|
+
@type
|
35
43
|
end
|
36
44
|
end
|
37
45
|
end
|
data/lib/eth/contract.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2016-
|
1
|
+
# Copyright (c) 2016-2025 The Ruby-Eth Contributors
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -25,7 +25,7 @@ module Eth
|
|
25
25
|
attr_accessor :key
|
26
26
|
attr_accessor :gas_limit, :gas_price, :max_fee_per_gas, :max_priority_fee_per_gas, :nonce
|
27
27
|
attr_accessor :bin, :name, :abi, :class_object
|
28
|
-
attr_accessor :events, :functions, :constructor_inputs
|
28
|
+
attr_accessor :events, :functions, :constructor_inputs, :errors
|
29
29
|
|
30
30
|
# Constructor of the {Eth::Contract} class.
|
31
31
|
#
|
@@ -44,7 +44,7 @@ module Eth
|
|
44
44
|
@name = _name
|
45
45
|
@bin = bin
|
46
46
|
@abi = abi
|
47
|
-
@constructor_inputs, @functions, @events = parse_abi(abi)
|
47
|
+
@constructor_inputs, @functions, @events, @errors = parse_abi(abi)
|
48
48
|
end
|
49
49
|
|
50
50
|
# Creates a contract wrapper from a Solidity file.
|
@@ -106,6 +106,52 @@ module Eth
|
|
106
106
|
end
|
107
107
|
end
|
108
108
|
|
109
|
+
# Finds a function by name.
|
110
|
+
#
|
111
|
+
# @param name [String] function name.
|
112
|
+
# @param args [Integer, nil] number of arguments of a function.
|
113
|
+
# @return [Eth::Contract::Function] function object.
|
114
|
+
# @raise [ArgumentError] if function not found.
|
115
|
+
def function(name, args: nil)
|
116
|
+
functions.find do |f|
|
117
|
+
f.name == name && (args.nil? || args == f.inputs.size)
|
118
|
+
end || raise(ArgumentError, "this function does not exist!")
|
119
|
+
end
|
120
|
+
|
121
|
+
# Finds an error by name.
|
122
|
+
#
|
123
|
+
# @param name [String] error name.
|
124
|
+
# @param args [Integer, nil] number of arguments of an error.
|
125
|
+
# @return [Eth::Contract::Error] error object.
|
126
|
+
# @raise [ArgumentError] if error not found.
|
127
|
+
def error(name, args: nil)
|
128
|
+
errors.find do |e|
|
129
|
+
e.name == name && (args.nil? || args == e.inputs.size)
|
130
|
+
end || raise(ArgumentError, "this error does not exist!")
|
131
|
+
end
|
132
|
+
|
133
|
+
# Decodes a custom error returned by an RPC error using the contract ABI.
|
134
|
+
#
|
135
|
+
# @param rpc_error [RpcError] the RPC error containing revert data.
|
136
|
+
# @return [String] a human readable error message.
|
137
|
+
def decode_error(rpc_error)
|
138
|
+
data = rpc_error.data
|
139
|
+
return rpc_error.message if data.nil? || errors.nil?
|
140
|
+
|
141
|
+
signature = data[0, 10]
|
142
|
+
if (err = errors.find { |e| e.signature == signature })
|
143
|
+
values = err.decode(data)
|
144
|
+
args = values&.map { |v| v.is_a?(String) ? v : v.inspect }&.join(",")
|
145
|
+
args ||= ""
|
146
|
+
"execution reverted: #{err.name}(#{args})"
|
147
|
+
elsif signature == "0x08c379a0"
|
148
|
+
reason = Abi.decode(["string"], "0x" + data[10..])&.first
|
149
|
+
"execution reverted: #{reason}"
|
150
|
+
else
|
151
|
+
rpc_error.message
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
109
155
|
# Create meta classes for smart contracts.
|
110
156
|
def build
|
111
157
|
class_name = @name
|
@@ -116,9 +162,12 @@ module Eth
|
|
116
162
|
def_delegators :parent, :name, :abi, :bin
|
117
163
|
def_delegators :parent, :gas_limit, :gas_price, :gas_limit=, :gas_price=, :nonce, :nonce=
|
118
164
|
def_delegators :parent, :max_fee_per_gas, :max_fee_per_gas=, :max_priority_fee_per_gas, :max_priority_fee_per_gas=
|
119
|
-
def_delegators :parent, :events
|
165
|
+
def_delegators :parent, :events, :errors
|
120
166
|
def_delegators :parent, :address, :address=
|
121
167
|
def_delegator :parent, :functions
|
168
|
+
def_delegator :parent, :function
|
169
|
+
def_delegator :parent, :error
|
170
|
+
def_delegator :parent, :decode_error
|
122
171
|
def_delegator :parent, :constructor_inputs
|
123
172
|
define_method :parent do
|
124
173
|
parent
|
@@ -140,7 +189,8 @@ module Eth
|
|
140
189
|
end
|
141
190
|
functions = abi.select { |x| x["type"] == "function" }.map { |fun| Eth::Contract::Function.new(fun) }
|
142
191
|
events = abi.select { |x| x["type"] == "event" }.map { |evt| Eth::Contract::Event.new(evt) }
|
143
|
-
[
|
192
|
+
errors = abi.select { |x| x["type"] == "error" }.map { |err| Eth::Contract::Error.new(err) }
|
193
|
+
[constructor_inputs, functions, events, errors]
|
144
194
|
end
|
145
195
|
end
|
146
196
|
end
|
@@ -151,3 +201,4 @@ require "eth/contract/function"
|
|
151
201
|
require "eth/contract/function_input"
|
152
202
|
require "eth/contract/function_output"
|
153
203
|
require "eth/contract/initializer"
|
204
|
+
require "eth/contract/error"
|
data/lib/eth/eip712.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2016-
|
1
|
+
# Copyright (c) 2016-2025 The Ruby-Eth Contributors
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -47,7 +47,12 @@ module Eth
|
|
47
47
|
|
48
48
|
# recursively look for further nested dependencies
|
49
49
|
types[primary_type.to_sym].each do |t|
|
50
|
-
|
50
|
+
nested_type = t[:type]
|
51
|
+
# unpack arrays to their inner types to resolve dependencies
|
52
|
+
if nested_type.end_with?("]")
|
53
|
+
nested_type = nested_type.partition("[").first
|
54
|
+
end
|
55
|
+
dependency = type_dependencies nested_type, types, result
|
51
56
|
end
|
52
57
|
return result
|
53
58
|
end
|
@@ -113,18 +118,12 @@ module Eth
|
|
113
118
|
types[primary_type.to_sym].each do |field|
|
114
119
|
value = data[field[:name].to_sym]
|
115
120
|
type = field[:type]
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
elsif type == "bytes"
|
121
|
-
encoded_types.push "bytes32"
|
122
|
-
value = Util.hex_to_bin value
|
123
|
-
encoded_values.push Util.keccak256 value
|
124
|
-
elsif !types[type.to_sym].nil?
|
121
|
+
if type.end_with?("]")
|
122
|
+
encoded_types.push type
|
123
|
+
encoded_values.push encode_array(type, value, types)
|
124
|
+
elsif type == "string" || type == "bytes" || !types[type.to_sym].nil?
|
125
125
|
encoded_types.push "bytes32"
|
126
|
-
|
127
|
-
encoded_values.push Util.keccak256 value
|
126
|
+
encoded_values.push encode_value(type, value, types)
|
128
127
|
else
|
129
128
|
encoded_types.push type
|
130
129
|
encoded_values.push value
|
@@ -135,6 +134,43 @@ module Eth
|
|
135
134
|
return Abi.encode encoded_types, encoded_values
|
136
135
|
end
|
137
136
|
|
137
|
+
# Encodes a single value according to its type following EIP-712 rules.
|
138
|
+
# Returns a 32-byte binary string.
|
139
|
+
def encode_value(type, value, types)
|
140
|
+
if type == "string"
|
141
|
+
return Util.keccak256 value
|
142
|
+
elsif type == "bytes"
|
143
|
+
value = Util.hex_to_bin value
|
144
|
+
return Util.keccak256 value
|
145
|
+
elsif !types[type.to_sym].nil?
|
146
|
+
nested = encode_data type, value, types
|
147
|
+
return Util.keccak256 nested
|
148
|
+
else
|
149
|
+
# encode basic types via ABI to get 32-byte representation
|
150
|
+
return Abi.encode([type], [value])
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# Prepares array values by encoding each element according to its
|
155
|
+
# base type. Returns an array compatible with Abi.encode.
|
156
|
+
def encode_array(type, value, types)
|
157
|
+
inner_type = type.slice(0, type.rindex("["))
|
158
|
+
return [] if value.nil?
|
159
|
+
value.map do |v|
|
160
|
+
if inner_type.end_with?("]")
|
161
|
+
encode_array inner_type, v, types
|
162
|
+
elsif inner_type == "string"
|
163
|
+
Util.keccak256 v
|
164
|
+
elsif inner_type == "bytes"
|
165
|
+
Util.keccak256 Util.hex_to_bin(v)
|
166
|
+
elsif !types[inner_type.to_sym].nil?
|
167
|
+
Util.keccak256 encode_data(inner_type, v, types)
|
168
|
+
else
|
169
|
+
v
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
138
174
|
# Recursively ABI-encodes and hashes all data and types.
|
139
175
|
#
|
140
176
|
# @param primary_type [String] the primary type which we want to hash.
|
data/lib/eth/ens/coin_type.rb
CHANGED
data/lib/eth/ens/resolver.rb
CHANGED
data/lib/eth/ens.rb
CHANGED
data/lib/eth/key/decrypter.rb
CHANGED
data/lib/eth/key/encrypter.rb
CHANGED
data/lib/eth/key.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2016-
|
1
|
+
# Copyright (c) 2016-2025 The Ruby-Eth Contributors
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -75,7 +75,7 @@ module Eth
|
|
75
75
|
signature = compact.bytes
|
76
76
|
v = Chain.to_v recovery_id, chain_id
|
77
77
|
leading_zero = true
|
78
|
-
[v].pack("
|
78
|
+
[v].pack("Q>").unpack("C*").each do |byte|
|
79
79
|
leading_zero = false if byte > 0 and leading_zero
|
80
80
|
signature.append byte unless leading_zero and byte === 0
|
81
81
|
end
|
data/lib/eth/rlp/decoder.rb
CHANGED
data/lib/eth/rlp/encoder.rb
CHANGED
data/lib/eth/rlp/sedes/binary.rb
CHANGED
data/lib/eth/rlp/sedes/list.rb
CHANGED
data/lib/eth/rlp/sedes.rb
CHANGED
data/lib/eth/rlp.rb
CHANGED
data/lib/eth/signature.rb
CHANGED
data/lib/eth/solidity.rb
CHANGED
data/lib/eth/tx/eip1559.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2016-
|
1
|
+
# Copyright (c) 2016-2025 The Ruby-Eth Contributors
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -78,7 +78,7 @@ module Eth
|
|
78
78
|
# @option params [Integer] :max_gas_fee the max transaction fee per gas.
|
79
79
|
# @option params [Integer] :gas_limit the gas limit.
|
80
80
|
# @option params [Eth::Address] :from the sender address.
|
81
|
-
# @option params [Eth::Address] :to the
|
81
|
+
# @option params [Eth::Address] :to the receiver address.
|
82
82
|
# @option params [Integer] :value the transaction value.
|
83
83
|
# @option params [String] :data the transaction data payload.
|
84
84
|
# @option params [Array] :access_list an optional access list.
|
@@ -148,13 +148,13 @@ module Eth
|
|
148
148
|
raise ParameterError, "Transaction missing fields!" if tx.size < 9
|
149
149
|
|
150
150
|
# populate the 9 payload fields
|
151
|
-
chain_id = Util.
|
152
|
-
nonce = Util.
|
153
|
-
priority_fee = Util.
|
154
|
-
max_gas_fee = Util.
|
155
|
-
gas_limit = Util.
|
151
|
+
chain_id = Util.deserialize_rlp_int tx[0]
|
152
|
+
nonce = Util.deserialize_rlp_int tx[1]
|
153
|
+
priority_fee = Util.deserialize_rlp_int tx[2]
|
154
|
+
max_gas_fee = Util.deserialize_rlp_int tx[3]
|
155
|
+
gas_limit = Util.deserialize_rlp_int tx[4]
|
156
156
|
to = Util.bin_to_hex tx[5]
|
157
|
-
value = Util.
|
157
|
+
value = Util.deserialize_rlp_int tx[6]
|
158
158
|
data = tx[7]
|
159
159
|
access_list = tx[8]
|
160
160
|
|
@@ -257,6 +257,31 @@ module Eth
|
|
257
257
|
return hash
|
258
258
|
end
|
259
259
|
|
260
|
+
# Signs the transaction with a provided signature blob.
|
261
|
+
#
|
262
|
+
# @param signature [String] the concatenated `r`, `s`, and `v` values.
|
263
|
+
# @return [String] a transaction hash.
|
264
|
+
# @raise [Signature::SignatureError] if transaction is already signed.
|
265
|
+
# @raise [Signature::SignatureError] if sender address does not match signer.
|
266
|
+
def sign_with(signature)
|
267
|
+
if Tx.signed? self
|
268
|
+
raise Signature::SignatureError, "Transaction is already signed!"
|
269
|
+
end
|
270
|
+
|
271
|
+
# ensure the sender address matches the signature
|
272
|
+
unless @sender.nil? or sender.empty?
|
273
|
+
public_key = Signature.recover(unsigned_hash, signature, @chain_id)
|
274
|
+
signer_address = Tx.sanitize_address Util.public_key_to_address(public_key).to_s
|
275
|
+
from_address = Tx.sanitize_address @sender
|
276
|
+
raise Signature::SignatureError, "Signer does not match sender" unless signer_address == from_address
|
277
|
+
end
|
278
|
+
|
279
|
+
r, s, v = Signature.dissect signature
|
280
|
+
recovery_id = Chain.to_recovery_id v.to_i(16), @chain_id
|
281
|
+
send :_set_signature, recovery_id, r, s
|
282
|
+
return hash
|
283
|
+
end
|
284
|
+
|
260
285
|
# Encodes a raw transaction object, wraps it in an EIP-2718 envelope
|
261
286
|
# with an EIP-1559 type prefix.
|
262
287
|
#
|
data/lib/eth/tx/eip2930.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2016-
|
1
|
+
# Copyright (c) 2016-2025 The Ruby-Eth Contributors
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -76,7 +76,7 @@ module Eth
|
|
76
76
|
# @option params [Integer] :gas_price the gas price.
|
77
77
|
# @option params [Integer] :gas_limit the gas limit.
|
78
78
|
# @option params [Eth::Address] :from the sender address.
|
79
|
-
# @option params [Eth::Address] :to the
|
79
|
+
# @option params [Eth::Address] :to the receiver address.
|
80
80
|
# @option params [Integer] :value the transaction value.
|
81
81
|
# @option params [String] :data the transaction data payload.
|
82
82
|
# @option params [Array] :access_list an optional access list.
|
@@ -145,12 +145,12 @@ module Eth
|
|
145
145
|
raise ParameterError, "Transaction missing fields!" if tx.size < 8
|
146
146
|
|
147
147
|
# populate the 8 payload fields
|
148
|
-
chain_id = Util.
|
149
|
-
nonce = Util.
|
150
|
-
gas_price = Util.
|
151
|
-
gas_limit = Util.
|
148
|
+
chain_id = Util.deserialize_rlp_int tx[0]
|
149
|
+
nonce = Util.deserialize_rlp_int tx[1]
|
150
|
+
gas_price = Util.deserialize_rlp_int tx[2]
|
151
|
+
gas_limit = Util.deserialize_rlp_int tx[3]
|
152
152
|
to = Util.bin_to_hex tx[4]
|
153
|
-
value = Util.
|
153
|
+
value = Util.deserialize_rlp_int tx[5]
|
154
154
|
data = tx[6]
|
155
155
|
access_list = tx[7]
|
156
156
|
|
@@ -251,6 +251,31 @@ module Eth
|
|
251
251
|
return hash
|
252
252
|
end
|
253
253
|
|
254
|
+
# Signs the transaction with a provided signature blob.
|
255
|
+
#
|
256
|
+
# @param signature [String] the concatenated `r`, `s`, and `v` values.
|
257
|
+
# @return [String] a transaction hash.
|
258
|
+
# @raise [Signature::SignatureError] if transaction is already signed.
|
259
|
+
# @raise [Signature::SignatureError] if sender address does not match signer.
|
260
|
+
def sign_with(signature)
|
261
|
+
if Tx.signed? self
|
262
|
+
raise Signature::SignatureError, "Transaction is already signed!"
|
263
|
+
end
|
264
|
+
|
265
|
+
# ensure the sender address matches the signature
|
266
|
+
unless @sender.nil? or sender.empty?
|
267
|
+
public_key = Signature.recover(unsigned_hash, signature, @chain_id)
|
268
|
+
signer_address = Tx.sanitize_address Util.public_key_to_address(public_key).to_s
|
269
|
+
from_address = Tx.sanitize_address @sender
|
270
|
+
raise Signature::SignatureError, "Signer does not match sender" unless signer_address == from_address
|
271
|
+
end
|
272
|
+
|
273
|
+
r, s, v = Signature.dissect signature
|
274
|
+
recovery_id = Chain.to_recovery_id v.to_i(16), @chain_id
|
275
|
+
send :_set_signature, recovery_id, r, s
|
276
|
+
return hash
|
277
|
+
end
|
278
|
+
|
254
279
|
# Encodes a raw transaction object, wraps it in an EIP-2718 envelope
|
255
280
|
# with an EIP-2930 type prefix.
|
256
281
|
#
|