evm-tx-input-decoder 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 11939dbfa42b580fe869a7cd33784265d6a273e978077dca73592e77523e8899
4
+ data.tar.gz: 62e1f39ce8521f75a5c9d5261219f409e28ae40bce42d982c04bfeefb2b909c5
5
+ SHA512:
6
+ metadata.gz: e299efb283d3c00107cbe730765603ce0a4fd52ba53099b15de3987bcf43ecad2bb72a182842b8f29e4f47212f5d89aeaa9559e9798d5f2457dd8aaadd110d10
7
+ data.tar.gz: 9c5fea8ca9640afe2456350e3c16ce91ff58925fb81f5ecf7bb2b1253e022e95f93ab2ace296e35be50fa877f61519dbcfb75fa64e1bb079f77dab0601eafb9a
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,16 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.7.0
3
+
4
+ Style/StringLiterals:
5
+ Enabled: true
6
+ EnforcedStyle: single_quotes
7
+
8
+ Style/StringLiteralsInInterpolation:
9
+ Enabled: true
10
+ EnforcedStyle: double_quotes
11
+
12
+ Layout/LineLength:
13
+ Max: 120
14
+
15
+ Style/Documentation:
16
+ Enabled: false
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2023-07-24
4
+
5
+ - Initial release
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in evm-tx-input-decoder.gemspec
6
+ gemspec
7
+
8
+ gem 'rake', '~> 13.0'
9
+ gem 'rspec', '~> 3.0'
10
+ gem 'rubocop', '~> 1.21'
data/Gemfile.lock ADDED
@@ -0,0 +1,81 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ evm-tx-input-decoder (0.1.0)
5
+ eth (~> 0.5)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ ast (2.4.2)
11
+ diff-lcs (1.5.0)
12
+ eth (0.5.10)
13
+ keccak (~> 1.3)
14
+ konstructor (~> 1.0)
15
+ openssl (>= 2.2, < 4.0)
16
+ rbsecp256k1 (~> 5.1)
17
+ scrypt (~> 3.0)
18
+ ffi (1.15.5)
19
+ ffi-compiler (1.0.1)
20
+ ffi (>= 1.0.0)
21
+ rake
22
+ json (2.6.3)
23
+ keccak (1.3.1)
24
+ konstructor (1.0.2)
25
+ mini_portile2 (2.8.4)
26
+ openssl (3.1.0)
27
+ parallel (1.22.1)
28
+ parser (3.2.1.1)
29
+ ast (~> 2.4.1)
30
+ pkg-config (1.5.2)
31
+ rainbow (3.1.1)
32
+ rake (13.0.6)
33
+ rbsecp256k1 (5.1.1)
34
+ mini_portile2 (~> 2.8)
35
+ pkg-config (~> 1.5)
36
+ rubyzip (~> 2.3)
37
+ regexp_parser (2.7.0)
38
+ rexml (3.2.5)
39
+ rspec (3.12.0)
40
+ rspec-core (~> 3.12.0)
41
+ rspec-expectations (~> 3.12.0)
42
+ rspec-mocks (~> 3.12.0)
43
+ rspec-core (3.12.2)
44
+ rspec-support (~> 3.12.0)
45
+ rspec-expectations (3.12.3)
46
+ diff-lcs (>= 1.2.0, < 2.0)
47
+ rspec-support (~> 3.12.0)
48
+ rspec-mocks (3.12.5)
49
+ diff-lcs (>= 1.2.0, < 2.0)
50
+ rspec-support (~> 3.12.0)
51
+ rspec-support (3.12.0)
52
+ rubocop (1.48.0)
53
+ json (~> 2.3)
54
+ parallel (~> 1.10)
55
+ parser (>= 3.2.0.0)
56
+ rainbow (>= 2.2.2, < 4.0)
57
+ regexp_parser (>= 1.8, < 3.0)
58
+ rexml (>= 3.2.5, < 4.0)
59
+ rubocop-ast (>= 1.26.0, < 2.0)
60
+ ruby-progressbar (~> 1.7)
61
+ unicode-display_width (>= 2.4.0, < 3.0)
62
+ rubocop-ast (1.27.0)
63
+ parser (>= 3.2.1.0)
64
+ ruby-progressbar (1.13.0)
65
+ rubyzip (2.3.2)
66
+ scrypt (3.0.7)
67
+ ffi-compiler (>= 1.0, < 2.0)
68
+ unicode-display_width (2.4.2)
69
+
70
+ PLATFORMS
71
+ x86_64-darwin-20
72
+ x86_64-linux
73
+
74
+ DEPENDENCIES
75
+ evm-tx-input-decoder!
76
+ rake (~> 13.0)
77
+ rspec (~> 3.0)
78
+ rubocop (~> 1.21)
79
+
80
+ BUNDLED WITH
81
+ 2.4.13
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2023 Ruslan Kotov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,67 @@
1
+ # EVM Transactions Input Decoder
2
+
3
+ This is a simple gem that helps decoding and encoding transactions input data for EVM based blockchains like Ethereum and Tron.
4
+
5
+ ## Installation
6
+ Run
7
+ ```bash
8
+ gem install evm-tx-input-decoder
9
+ ```
10
+ or add
11
+ ```ruby
12
+ gem 'evm-tx-input-decoder', require: 'evm_tx_input'
13
+ ```
14
+ to your Gemfile.
15
+
16
+ ## Usage
17
+
18
+ ### Decoding
19
+ Let's consider decoding process by example [USDT transaction](https://etherscan.io/tx/0x93ae1b191189aa27833b65f3668ae7704f9b7d9badabf4a9a16e53d84e1a3472) in an Ethereum blockchain.
20
+
21
+ The input data is `0xa9059cbb00000000000000000000000003cb76e200ba785f6008c12933aa3640536d2011000000000000000000000000000000000000000000000000000000a083712e00`, which can be found in `More details` section.
22
+
23
+ The USDT token ABI can be found by [this url](http://api.etherscan.io/api?module=contract&action=getabi&address=0xdac17f958d2ee523a2206206994597c13d831ec7&format=raw)
24
+
25
+ ```ruby
26
+ require 'evm_tx'
27
+
28
+ json = URI.open('http://api.etherscan.io/api?module=contract&action=getabi&address=0xdac17f958d2ee523a2206206994597c13d831ec7&format=raw') { |file| jsonfile.read }
29
+ abi = JSON.parse(json)
30
+ input = '0xa9059cbb00000000000000000000000003cb76e200ba785f6008c12933aa3640536d2011000000000000000000000000000000000000000000000000000000a083712e00'
31
+
32
+ function = EvmTxInput::Decoder.new(abi).decode_input(input)
33
+ function.id #=> "a9059cbb"
34
+ function.name #=> "transfer"
35
+ function.arguments
36
+ # [#<EvmTxInput::Argument:0x00000001107ffa60 @name="_to", @type="address", @value="0x03cb76e200ba785f6008c12933aa3640536d2011">,
37
+ # #<EvmTxInput::Argument:0x00000001107ffa10 @name="_value", @type="uint256", @value=689400000000>]
38
+ ```
39
+
40
+ ### Encoding
41
+ Following decoding procedure let's encode the previous result.
42
+
43
+ ```ruby
44
+ require 'evm_tx'
45
+
46
+ function_name = 'transfer'
47
+ types = %w[address uint256]
48
+ args = ['0x03cb76e200ba785f6008c12933aa3640536d2011', 689400000000]
49
+ EvmTxInput::Encoder.encode_input(function_name, types, args)
50
+ #=> "0xa9059cbb00000000000000000000000003cb76e200ba785f6008c12933aa3640536d2011000000000000000000000000000000000000000000000000000000a083712e00"
51
+ ```
52
+
53
+ For more details read the [documentation](https://rubydoc.info/github/rkotov93/evm-tx-input-decoder/main/EvmTx).
54
+
55
+ ## Development
56
+
57
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
58
+
59
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
60
+
61
+ ## Contributing
62
+
63
+ Bug reports and pull requests are welcome on GitHub at https://github.com/rkotov93/evm-tx-input-decoder.
64
+
65
+ ## License
66
+
67
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require 'rubocop/rake_task'
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/evm_tx_input/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'evm-tx-input-decoder'
7
+ spec.version = EvmTxInput::VERSION
8
+ spec.authors = ['Ruslan Kotov']
9
+ spec.email = ['rkotov93@gmail.com']
10
+
11
+ spec.summary = 'Simple gem to decode and encode EVM transactions input data'
12
+ spec.description = 'This is a simple gem that helps decoding and encoding transactions input data'\
13
+ 'for EVM based blockchains like Ethereum and Tron.'
14
+ spec.homepage = 'https://github.com/rkotov93/evm-tx-input-decoder'
15
+ spec.license = 'MIT'
16
+ spec.required_ruby_version = '>= 2.7.0'
17
+
18
+ # spec.metadata['allowed_push_host'] = "Set to your gem server 'https://example.com'"
19
+
20
+ spec.metadata['homepage_uri'] = spec.homepage
21
+ spec.metadata['source_code_uri'] = 'https://github.com/rkotov93/evm-tx-input-decoder'
22
+ spec.metadata['changelog_uri'] = 'https://github.com/rkotov93/evm-tx-input-decoder/CHANGELOG.md'
23
+
24
+ # Specify which files should be added to the gem when it is released.
25
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
26
+ spec.files = Dir.chdir(__dir__) do
27
+ `git ls-files -z`.split("\x0").reject do |f|
28
+ (File.expand_path(f) == __FILE__) || f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor])
29
+ end
30
+ end
31
+ spec.bindir = 'exe'
32
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
33
+ spec.require_paths = %w[lib]
34
+
35
+ # Uncomment to register a new dependency of your gem
36
+ spec.add_dependency 'eth', '~> 0.5'
37
+
38
+ # For more information and examples about making a new gem, check out our
39
+ # guide at: https://bundler.io/guides/creating_gem.html
40
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EvmTxInput
4
+ # Represents decoded smart contract function arguments
5
+ #
6
+ # @attr_reader name [String] name of function argument
7
+ # @attr_reader type [String] type of function argument
8
+ # @attr_reader value [String, Integer] value of function argument
9
+ class Argument
10
+ attr_reader :name, :type, :value
11
+
12
+ def initialize(name, type, value)
13
+ @name = name
14
+ @type = type
15
+ @value = value
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EvmTxInput
4
+ # A class containing a set of helpers to decode transactions input data
5
+ # into human-readable values by provided contract's ABI
6
+ #
7
+ # @attr_reader abi [Hash] parsed contract ABI
8
+ # @attr_reader method_definition [Hash] parsed contract ABI
9
+ class Decoder
10
+ attr_reader :abi, :method_definitions
11
+
12
+ # Constructor of EvmTxInput::Decoder
13
+ #
14
+ # @param abi [Hash] parsed contract ABI
15
+ def initialize(abi = {})
16
+ @abi = abi
17
+ @method_definitions = method_definitions_by_id(abi)
18
+ end
19
+
20
+ # Decodes transaction input data
21
+ #
22
+ # @param input_data [String] binary encoded input data from transaction
23
+ # @return [EvmTxInput::Function]
24
+ def decode_input(input_data)
25
+ input_data = input_data[2..] if input_data.start_with?('0x')
26
+ method_id = input_data[0...8]
27
+ definition = method_definitions[method_id]
28
+ raise Error, "ABI does not contain method with #{method_id} ID" unless definition
29
+
30
+ Function.new(method_id, definition['name'], extract_arguments(input_data, definition))
31
+ end
32
+
33
+ private
34
+
35
+ def method_definitions_by_id(abi)
36
+ abi.each_with_object({}) do |method_definition, obj|
37
+ type = method_definition['type']
38
+ next if type == 'event'
39
+
40
+ method_id = calculate_method_id(method_definition)
41
+ obj[method_id] = method_definition
42
+ end
43
+ end
44
+
45
+ def calculate_method_id(method_definition)
46
+ function_name = method_definition['name']
47
+ arg_types = method_definition['inputs'].map { |input| input['type'] }.join(',')
48
+ function_signature = "#{function_name}(#{arg_types})"
49
+
50
+ Eth::Util.bin_to_hex(Eth::Util.keccak256(function_signature)[0...4])
51
+ end
52
+
53
+ def extract_arguments(input_data, definition)
54
+ args_data = input_data[8..]
55
+ arg_types = definition['inputs'].map { |input| input['type'] }
56
+ arg_values = Eth::Abi.decode(arg_types, args_data)
57
+
58
+ definition['inputs'].map.with_index do |input, i|
59
+ Argument.new(input['name'], input['type'], arg_values[i])
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EvmTxInput
4
+ # A class containing a set of helpers to encode human-readable values
5
+ # to binary transactions input data
6
+ class Encoder
7
+ class << self
8
+ # Encodes function, types and arguments into binary input data
9
+ #
10
+ # @param function_name [String] the name of calling smart contract function, e.g. `transfer`
11
+ # @param types [Array<String>] list of argument types, e.g. `['address', 'uint256']`
12
+ # @param types [Array<String>] list of arguments, e.g. `['0x21a31ee1afc51d94c2efccaa2092ad1028285549', 100000]`
13
+ # @return [String] binary representation of input data
14
+ def encode_input(function_name, types = [], args = [])
15
+ encoded_function_signature = encode_function_signature(function_name, types)
16
+ encoded_params = encode_parameters(types, args)
17
+
18
+ "0x#{encoded_function_signature}#{encoded_params}"
19
+ end
20
+
21
+ # Encodes function into binary representation (first 8 symbols at input data)
22
+ #
23
+ # @param function_name [String] the name of calling smart contract function, e.g. `transfer`
24
+ # @param types [Array<String>] list of argument types, e.g. `['address', 'uint256']`
25
+ # @return [String] binary representation of function
26
+ def encode_function_signature(function_name, types = [])
27
+ function_signature = "#{function_name}(#{types.join(",")})"
28
+ Eth::Util.bin_to_hex(Eth::Util.keccak256(function_signature)[0...4])
29
+ end
30
+
31
+ # Encodes arguments into binary input data
32
+ #
33
+ # @param types [Array<String>] list of argument types, e.g. `['address', 'uint256']`
34
+ # @param types [Array<String>] list of arguments, e.g. `['0x21a31ee1afc51d94c2efccaa2092ad1028285549', 100000]`
35
+ # @return [String] binary representation of arguments
36
+ def encode_parameters(types = [], args = [])
37
+ Eth::Abi.encode(types, args).unpack1('H*')
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EvmTxInput
4
+ class Error < StandardError; end
5
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EvmTxInput
4
+ # Represent decoded smart contract function call
5
+ #
6
+ # @attr_reader id [String] first 8 symbols of transaction input data
7
+ # @attr_reader name [String] name of smart contract function
8
+ # @attr_reader arguments [Array<EvmTxInput::Argument>] a list of function arguments
9
+ class Function
10
+ attr_reader :id, :name, :arguments
11
+
12
+ def initialize(id, name, arguments = [])
13
+ @id = id
14
+ @name = name
15
+ @arguments = arguments
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EvmTxInput
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'eth'
4
+
5
+ require_relative 'evm_tx_input/version'
6
+ require_relative 'evm_tx_input/decoder'
7
+ require_relative 'evm_tx_input/encoder'
8
+ require_relative 'evm_tx_input/function'
9
+ require_relative 'evm_tx_input/argument'
10
+ require_relative 'evm_tx_input/error'
11
+
12
+ module EvmTxInput
13
+ class Error < StandardError; end
14
+ end
data/sig/evm_tx.rbs ADDED
@@ -0,0 +1,4 @@
1
+ module EvmTxInput
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: evm-tx-input-decoder
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ruslan Kotov
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-08-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: eth
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.5'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.5'
27
+ description: This is a simple gem that helps decoding and encoding transactions input
28
+ datafor EVM based blockchains like Ethereum and Tron.
29
+ email:
30
+ - rkotov93@gmail.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - ".rspec"
36
+ - ".rubocop.yml"
37
+ - CHANGELOG.md
38
+ - Gemfile
39
+ - Gemfile.lock
40
+ - LICENSE.txt
41
+ - README.md
42
+ - Rakefile
43
+ - evm-tx-input-decoder.gemspec
44
+ - lib/evm_tx_input.rb
45
+ - lib/evm_tx_input/argument.rb
46
+ - lib/evm_tx_input/decoder.rb
47
+ - lib/evm_tx_input/encoder.rb
48
+ - lib/evm_tx_input/error.rb
49
+ - lib/evm_tx_input/function.rb
50
+ - lib/evm_tx_input/version.rb
51
+ - sig/evm_tx.rbs
52
+ homepage: https://github.com/rkotov93/evm-tx-input-decoder
53
+ licenses:
54
+ - MIT
55
+ metadata:
56
+ homepage_uri: https://github.com/rkotov93/evm-tx-input-decoder
57
+ source_code_uri: https://github.com/rkotov93/evm-tx-input-decoder
58
+ changelog_uri: https://github.com/rkotov93/evm-tx-input-decoder/CHANGELOG.md
59
+ post_install_message:
60
+ rdoc_options: []
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: 2.7.0
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ requirements: []
74
+ rubygems_version: 3.4.13
75
+ signing_key:
76
+ specification_version: 4
77
+ summary: Simple gem to decode and encode EVM transactions input data
78
+ test_files: []