Full Code of q9f/eth.rb for AI

main 87cafff8254b cached
136 files
7.4 MB
2.0M tokens
550 symbols
1 requests
Download .txt
Showing preview only (7,928K chars total). Download the full file or copy to clipboard to get everything.
Repository: q9f/eth.rb
Branch: main
Commit: 87cafff8254b
Files: 136
Total size: 7.4 MB

Directory structure:
gitextract_urvyeq_7/

├── .github/
│   ├── dependabot.yml
│   └── workflows/
│       ├── codeql.yml
│       ├── docs.yml
│       └── spec.yml
├── .gitignore
├── .gitmodules
├── .yardopts
├── AUTHORS.txt
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Gemfile
├── LICENSE.txt
├── README.md
├── Rakefile
├── SECURITY.md
├── abi/
│   ├── ens_registry.json
│   └── ens_resolver.json
├── bin/
│   ├── console
│   └── setup
├── codecov.yml
├── eth.gemspec
├── lib/
│   ├── eth/
│   │   ├── abi/
│   │   │   ├── decoder.rb
│   │   │   ├── encoder.rb
│   │   │   ├── event.rb
│   │   │   ├── function.rb
│   │   │   ├── packed/
│   │   │   │   └── encoder.rb
│   │   │   └── type.rb
│   │   ├── abi.rb
│   │   ├── address.rb
│   │   ├── api.rb
│   │   ├── bls.rb
│   │   ├── chain.rb
│   │   ├── client/
│   │   │   ├── http.rb
│   │   │   ├── ipc.rb
│   │   │   └── ws.rb
│   │   ├── client.rb
│   │   ├── constant.rb
│   │   ├── contract/
│   │   │   ├── error.rb
│   │   │   ├── event.rb
│   │   │   ├── function.rb
│   │   │   ├── function_input.rb
│   │   │   ├── function_output.rb
│   │   │   └── initializer.rb
│   │   ├── contract.rb
│   │   ├── eip712.rb
│   │   ├── ens/
│   │   │   ├── coin_type.rb
│   │   │   └── resolver.rb
│   │   ├── ens.rb
│   │   ├── key/
│   │   │   ├── decrypter.rb
│   │   │   └── encrypter.rb
│   │   ├── key.rb
│   │   ├── rlp/
│   │   │   ├── decoder.rb
│   │   │   ├── encoder.rb
│   │   │   ├── sedes/
│   │   │   │   ├── big_endian_int.rb
│   │   │   │   ├── binary.rb
│   │   │   │   └── list.rb
│   │   │   └── sedes.rb
│   │   ├── rlp.rb
│   │   ├── signature.rb
│   │   ├── solidity.rb
│   │   ├── tx/
│   │   │   ├── eip1559.rb
│   │   │   ├── eip2930.rb
│   │   │   ├── eip4844.rb
│   │   │   ├── eip7702.rb
│   │   │   └── legacy.rb
│   │   ├── tx.rb
│   │   ├── unit.rb
│   │   ├── util.rb
│   │   └── version.rb
│   └── eth.rb
└── spec/
    ├── eth/
    │   ├── abi/
    │   │   ├── decoder_spec.rb
    │   │   ├── encoder_spec.rb
    │   │   ├── event_spec.rb
    │   │   ├── function_spec.rb
    │   │   ├── packed/
    │   │   │   └── encoder_spec.rb
    │   │   └── type_spec.rb
    │   ├── abi_spec.rb
    │   ├── address_spec.rb
    │   ├── bls_spec.rb
    │   ├── chain_spec.rb
    │   ├── client/
    │   │   └── ws_spec.rb
    │   ├── client_spec.rb
    │   ├── constant_spec.rb
    │   ├── contract/
    │   │   ├── error_spec.rb
    │   │   ├── event_spec.rb
    │   │   ├── function_input_spec.rb
    │   │   ├── function_output_spec.rb
    │   │   ├── function_spec.rb
    │   │   └── initializer_spec.rb
    │   ├── contract_spec.rb
    │   ├── eip712_spec.rb
    │   ├── ens/
    │   │   ├── coin_type_spec.rb
    │   │   └── resolver_spec.rb
    │   ├── ens_spec.rb
    │   ├── key/
    │   │   ├── decrypter_spec.rb
    │   │   └── encrypter_spec.rb
    │   ├── key_spec.rb
    │   ├── rlp/
    │   │   ├── sedes/
    │   │   │   ├── big_endian_int_spec.rb
    │   │   │   ├── binary_spec.rb
    │   │   │   └── list_spec.rb
    │   │   └── sedes_spec.rb
    │   ├── rlp_spec.rb
    │   ├── signature_spec.rb
    │   ├── solidity_spec.rb
    │   ├── tx/
    │   │   ├── eip1559_spec.rb
    │   │   ├── eip2930_spec.rb
    │   │   ├── eip4844_spec.rb
    │   │   ├── eip7702_spec.rb
    │   │   └── legacy_spec.rb
    │   ├── tx_spec.rb
    │   ├── unit_spec.rb
    │   └── util_spec.rb
    ├── eth_spec.rb
    ├── fixtures/
    │   ├── abi/
    │   │   ├── ENSRegistryWithFallback.json
    │   │   ├── ERC1155.json
    │   │   ├── ERC20.json
    │   │   ├── ERC721.json
    │   │   ├── Tuple.json
    │   │   ├── Tuple2.json
    │   │   └── ethers.json
    │   ├── contracts/
    │   │   ├── address_storage.sol
    │   │   ├── deposit.sol
    │   │   ├── dummy.sol
    │   │   ├── erc20.sol
    │   │   ├── error.sol
    │   │   ├── greeter.sol
    │   │   ├── signer.sol
    │   │   ├── simple_registry.sol
    │   │   ├── test_contract.sol
    │   │   ├── tuple.sol
    │   │   └── tuple2.sol
    │   └── keys/
    │       ├── testingtesting.json
    │       ├── testpassword.json
    │       └── testunknownkdf.json
    └── spec_helper.rb

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/dependabot.yml
================================================
---
updates:
  -
    directory: /
    labels:
      - dependencies
    package-ecosystem: bundler
    schedule:
      interval: weekly
    versioning-strategy: increase
  -
    directory: /
    labels:
      - operations
    package-ecosystem: github-actions
    schedule:
      interval: monthly
version: 2


================================================
FILE: .github/workflows/codeql.yml
================================================
---
name: CodeQL

on:
  pull_request:
    branches:
      - main
  push:
    branches:
      - main

jobs:
  analyze:
    name: Analyze
    runs-on: ubuntu-latest
    permissions:
      actions: read
      contents: read
      security-events: write
    strategy:
      fail-fast: false
      matrix:
        language:
          - ruby
    steps:
      - name: "Checkout repository"
        uses: actions/checkout@v6
      - name: "Initialize CodeQL"
        uses: github/codeql-action/init@v4
        with:
          languages: "${{ matrix.language }}"
      - name: Autobuild
        uses: github/codeql-action/autobuild@v4
      - name: "Perform CodeQL Analysis"
        uses: github/codeql-action/analyze@v4
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: '3.4'
          bundler-cache: true
      - name: "Run rufo code formatting checks"
        run: |
          gem install rufo
          rufo --check ./lib
          rufo --check ./spec
      - name: "Run yard documentation checks"
        run: |
          gem install yard
          yard doc --fail-on-warning


================================================
FILE: .github/workflows/docs.yml
================================================
---
name: Docs

on:
  push:
    branches:
      - main

jobs:
  docs:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v6
    - uses: ruby/setup-ruby@v1
      with:
        ruby-version: '3.4'
        bundler-cache: true
    - name: Run Yard Doc
      run: |
        gem install yard
        yard doc
    - name: Deploy GH Pages
      uses: JamesIves/github-pages-deploy-action@v4.8.0
      with:
          branch: gh-pages
          folder: doc/


================================================
FILE: .github/workflows/spec.yml
================================================
---
name: Spec

on:
  pull_request:
    branches:
      - main
  push:
    branches:
      - main
  schedule:
    -
      cron: "45 3 * * *"

jobs:
  test:
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, macos-latest]
        ruby: ['3.4', '4.0']
    steps:
    - uses: actions/checkout@v6
    - name: MacOs Dependencies
      if: matrix.os == 'macos-latest'
      run: |
        brew update
        brew tap ethereum/ethereum
        brew install --verbose autoconf automake libtool pkg-config autogen geth solidity
    - name: Ubuntu Dependencies
      if: matrix.os == 'ubuntu-latest'
      run: |
        sudo add-apt-repository -y ppa:ethereum/ethereum
        sudo apt-get update
        sudo apt-get install -y autoconf automake libtool pkg-config geth solc
    - uses: ruby/setup-ruby@v1
      with:
        ruby-version: ${{ matrix.ruby }}
        bundler-cache: true
    - name: Run Geth
      run: |
        geth --dev \
             --http \
             --ws \
             --ipcpath /tmp/geth.ipc \
             >/tmp/geth.log 2>&1 &
        echo $! > /tmp/geth.pid
        sleep 10
    - name: Gem Dependencies
      run: |
        git submodule update --init --recursive
    - name: Run Tests
      run: |
        bundle exec rspec
    - name: Stop Geth
      if: always()
      run: |
        if [ -f /tmp/geth.pid ]; then
          kill "$(cat /tmp/geth.pid)" 2>/dev/null || true
        fi
    - name: Geth Logs (on failure)
      if: failure()
      run: |
        if [ -f /tmp/geth.log ]; then
          echo "===== geth log ====="
          tail -n 200 /tmp/geth.log
        fi
    - name: Upload coverage to Codecov
      uses: codecov/codecov-action@v6
      with:
        fail_ci_if_error: true
        token: ${{ secrets.CODECOV_TOKEN }}


================================================
FILE: .gitignore
================================================
*.DS_Store

*.o
*.so
*.gem
*.log
*.rbc
.config
.rake_tasks~
coverage/
InstalledFiles
pkg/
tmp/

# RSpec configuration and generated files:
.rspec
spec/examples.txt

# Documentation cache and generated files:
.yardoc/
_yardoc/
doc/
rdoc/

# Environment normalization:
.bundle/
vendor/bundle/*
!vendor/bundle/.keep
lib/bundler/man/

# For a library or gem, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
Gemfile.lock
.ruby-version
.ruby-gemset

# Unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
.rvmrc

# NodeJS stuff
node_modules
package.json
package-lock.json


================================================
FILE: .gitmodules
================================================
[submodule "spec/fixtures/ethereum/tests"]
	path = spec/fixtures/ethereum/tests
	url = https://github.com/ethereum/tests.git


================================================
FILE: .yardopts
================================================
--verbose --fail-on-warning --markup markdown --embed-mixins


================================================
FILE: AUTHORS.txt
================================================
The Ruby-Eth Contributors are:
* Steve Ellis @se3000
* Afri Schoedon @q9f
* John Omar @chainoperator
* Joshua Peek @josh
* Yuta Kurotaki @kurotaky

See also:
* https://github.com/q9f/eth.rb/graphs/contributors

The Ruby-Eth project was maintained 2016-2020 in Steve Ellis's (@se3000)
repository licensed under MIT conditions:
* https://github.com/se3000/ruby-eth

The latest Ruby-Eth gem is not only a rewrite of the aforementioned gem 
but also a partial merge of the Ethereum.rb Ruby Ethereum library by
Marek Kirejczyk (@marekkirejczyk) and Yuta Kurotaki (@kurotaky) licensed 
under MIT conditions:
* https://github.com/EthWorks/ethereum.rb

The latest version of the Ruby-Eth gem includes a revised version of the
ABI gem by Jan Xie (@janx) and Zhang Yaning (@u2) licensed under MIT
conditions:
* https://github.com/cryptape/ruby-ethereum-abi

The latest version of the Ruby-Eth gem contains a condensed version of the
RLP gem by Jan Xie (@janx) and Zhang Yaning (@u2) licensed under MIT
conditions:
* https://github.com/cryptape/ruby-rlp


================================================
FILE: CHANGELOG.md
================================================
# Change Log
All notable changes to this project will be documented in this file.

## [0.5.15]
### Added
* Implement EIP712 array encoding [#361](https://github.com/q9f/eth.rb/pull/361)
* Support nested dynamic arrays in ABI [#356](https://github.com/q9f/eth.rb/pull/356)
* Allow signing transactions with external signatures [#349](https://github.com/q9f/eth.rb/pull/349)
* Feat: add eip-4844 transactions [#345](https://github.com/q9f/eth.rb/pull/345)
* Support Solidity custom errors per ERC-6093 [#344](https://github.com/q9f/eth.rb/pull/344)
* Allow to use chains with id > 4294967295 [#337](https://github.com/q9f/eth.rb/pull/337)

### Changed
* Harden ABI type parsing [#358](https://github.com/q9f/eth.rb/pull/358)
* Ensure ABI decoder rejects ZST offsets [#359](https://github.com/q9f/eth.rb/pull/359)
* Test: decode eip4844 blobs [#360](https://github.com/q9f/eth.rb/pull/360)
* Abi: decode transaction input [#354](https://github.com/q9f/eth.rb/pull/354)
* Fix tuple output decoding for contract calls [#353](https://github.com/q9f/eth.rb/pull/353)
* Add comprehensive Tx module tests [#352](https://github.com/q9f/eth.rb/pull/352)
* Move error decoding to contract module [#350](https://github.com/q9f/eth.rb/pull/350)
* Enforce minimal RLP integer decoding [#351](https://github.com/q9f/eth.rb/pull/351)
* Fix tuple size calculation without components [#348](https://github.com/q9f/eth.rb/pull/348)
* Docs: update readme [#347](https://github.com/q9f/eth.rb/pull/347)
* Chore: update development dependencies [#346](https://github.com/q9f/eth.rb/pull/346)
* Handle hex string inputs in big-endian conversion [#343](https://github.com/q9f/eth.rb/pull/343)
* Handle uppercase hex prefixes [#339](https://github.com/q9f/eth.rb/pull/339)
* Add methods to encode function call and decode its result [#334](https://github.com/q9f/eth.rb/pull/334)
* Docs(util): fix hex? return type [#342](https://github.com/q9f/eth.rb/pull/342)
* Handle hex input consistently in int_to_big_endian [#341](https://github.com/q9f/eth.rb/pull/341)
* Fix receiver option spelling [#340](https://github.com/q9f/eth.rb/pull/340)
* Chore: bump version to 0.5.15 [#333](https://github.com/q9f/eth.rb/pull/333)

## [0.5.14]
### Added
* Add ability to decode event parameters using ABI reference. [#328](https://github.com/q9f/eth.rb/pull/328)
* Add support for EIP-7702 transactions  [#320](https://github.com/q9f/eth.rb/pull/320)
* Eth/abi: implement packed encoder [#310](https://github.com/q9f/eth.rb/pull/310)

### Changed
* Chore: run rufo, add docs [#332](https://github.com/q9f/eth.rb/pull/332)
* Spec/client: fix nonce too low error handling in spec [#331](https://github.com/q9f/eth.rb/pull/331)
* Move the tests that are failing due to a geth upgrade to pending  [#330](https://github.com/q9f/eth.rb/pull/330)
* Spec/client: don't require any rpc api token for tests [#326](https://github.com/q9f/eth.rb/pull/326)
* Build(deps): bump JamesIves/github-pages-deploy-action from 4.7.2 to 4.7.3 [#327](https://github.com/q9f/eth.rb/pull/327)
* Eth/eip712: prepare tests for packed encoding [#216](https://github.com/q9f/eth.rb/pull/216)
* Spec/solidity: mute system call output [#319](https://github.com/q9f/eth.rb/pull/319)
* Updated nesting of describe blocks in the EIP-1559 spec. [#318](https://github.com/q9f/eth.rb/pull/318)
* Update README.md [#317](https://github.com/q9f/eth.rb/pull/317)
* Docs: update README.md [#314](https://github.com/q9f/eth.rb/pull/314)
* Gem: update copyright headers [#312](https://github.com/q9f/eth.rb/pull/312)
* Build(deps): bump JamesIves/github-pages-deploy-action from 4.7.1 to 4.7.2 [#309](https://github.com/q9f/eth.rb/pull/309)
* Spec: switch from infura to drpc [#308](https://github.com/q9f/eth.rb/pull/308)
* Ci: update ruby version [#307](https://github.com/q9f/eth.rb/pull/307)
* Gem: bump version to 0.5.14 [#305](https://github.com/q9f/eth.rb/pull/305)
* Docs: update changelog [#304](https://github.com/q9f/eth.rb/pull/304)

## [0.5.13]
### Changed
* Eth/api: update to latest available go-ethereum apis [#301](https://github.com/q9f/eth.rb/pull/301)
* Eth/chain: update ids [#300](https://github.com/q9f/eth.rb/pull/300)
* Spec: update ethereum/tests fixtures [#303](https://github.com/q9f/eth.rb/pull/303)
* Ci: fix codecov uploader [#302](https://github.com/q9f/eth.rb/pull/302)
* Eth/tx: only enforce block gas limit on mainnet [#299](https://github.com/q9f/eth.rb/pull/299)
* Eth/util: fix single-byte hex-string nibbles [#298](https://github.com/q9f/eth.rb/pull/298)
* Eth/address: rename null address to zero address [#297](https://github.com/q9f/eth.rb/pull/297)
* Eth/address: add support to check for the ethereum "null address" [#296](https://github.com/q9f/eth.rb/pull/296)
* Build(deps): bump codecov/codecov-action from 4 to 5 [#295](https://github.com/q9f/eth.rb/pull/295)
* Build(deps): bump JamesIves/github-pages-deploy-action [#294](https://github.com/q9f/eth.rb/pull/294)
* Build(deps): bump JamesIves/github-pages-deploy-action [#288](https://github.com/q9f/eth.rb/pull/288)
* Eth/client: always return hash even if transaction didn't succeed [#284](https://github.com/q9f/eth.rb/pull/284)
* Eth/chain: update list of chains [#283](https://github.com/q9f/eth.rb/pull/283)
* Fix undefined method `raise_error' for an instance of Eth::Tx::Eip1559 (NoMethodError) [#282](https://github.com/q9f/eth.rb/pull/282)
* Gem: bump version to 0.5.13 [#281](https://github.com/q9f/eth.rb/pull/281)

## [0.5.12]
### Added
* Allow to call JSON RPC with custom block number [#268](https://github.com/q9f/eth.rb/pull/268)
* Support tuple params in EventLog [#276](https://github.com/q9f/eth.rb/pull/276)

### Changed
* Eth: update version [#280](https://github.com/q9f/eth.rb/pull/280)
* Eth/abi: fix negative integer coding [#279](https://github.com/q9f/eth.rb/pull/279)
* Support negative number from JSON RPC [#267](https://github.com/q9f/eth.rb/pull/267)
* Abi/event: confirm decoding tuples works [#278](https://github.com/q9f/eth.rb/pull/278)
* Allow to call JSON RPC with custom block number [#268](https://github.com/q9f/eth.rb/pull/268)
* Gem: run rufo [#277](https://github.com/q9f/eth.rb/pull/277)
* Fix event signature [#250](https://github.com/q9f/eth.rb/pull/250)
* Support tuple params in EventLog [#276](https://github.com/q9f/eth.rb/pull/276)
* Ci: update ruby version [#271](https://github.com/q9f/eth.rb/pull/271)
* Eth/api: remove coinbase as default account [#269](https://github.com/q9f/eth.rb/pull/269)
* Build(deps): bump JamesIves/github-pages-deploy-action from 4.5.0 to 4.6.1 [#275](https://github.com/q9f/eth.rb/pull/275)
* Build(deps): bump github/codeql-action from 2 to 3 [#257](https://github.com/q9f/eth.rb/pull/257)
* Build(deps): bump JamesIves/github-pages-deploy-action from 4.4.3 to 4.5.0 [#256](https://github.com/q9f/eth.rb/pull/256)
* Fix typo in contract_spec.rb [#253](https://github.com/q9f/eth.rb/pull/253)
* Eth/eip721: fix data type bug for bytes, fix #251 [#252](https://github.com/q9f/eth.rb/pull/252)
* Ci: unpatch geth [#248](https://github.com/q9f/eth.rb/pull/248)
* Build(deps): bump actions/checkout from 3 to 4 [#246](https://github.com/q9f/eth.rb/pull/246)

## [0.5.11]
### Added
* Eth/abi: allow encoding address types [#242](https://github.com/q9f/eth.rb/pull/242)
* Eth/solidity: enable --via-ir [#232](https://github.com/q9f/eth.rb/pull/232)
* Checking userinfo with the uri method [#233](https://github.com/q9f/eth.rb/pull/233)
* Eth/abi: add abicoder gem tests collection [#218](https://github.com/q9f/eth.rb/pull/218)
* Manual default_account [#215](https://github.com/q9f/eth.rb/pull/215)
* Add moonbeam networks in [#209](https://github.com/q9f/eth.rb/pull/209)

### Changed
* Spec: run rufo [#245](https://github.com/q9f/eth.rb/pull/245)
* Fix the decoding of unsigned transactions [#243](https://github.com/q9f/eth.rb/pull/243)
* Build(deps): bump JamesIves/github-pages-deploy-action from 4.4.2 to 4.4.3 [#244](https://github.com/q9f/eth.rb/pull/244)
* Build(deps): bump JamesIves/github-pages-deploy-action from 4.4.1 to 4.4.2 [#240](https://github.com/q9f/eth.rb/pull/240)
* Eth/tx: update tx initcode cost for shanghai [#237](https://github.com/q9f/eth.rb/pull/237)
* Eth/client: remove default gas limit attribute [#235](https://github.com/q9f/eth.rb/pull/235)
* Docs: minor fixups [#229](https://github.com/q9f/eth.rb/pull/229)
* Eth/contract: ensure contract name is title case [#228](https://github.com/q9f/eth.rb/pull/228)
* Deps: require forwardable for contracts [#227](https://github.com/q9f/eth.rb/pull/227)
* Ens/resolver: remove pending for etc coin type [#219](https://github.com/q9f/eth.rb/pull/219)
* Deps: update secp256k1 to 6 [#214](https://github.com/q9f/eth.rb/pull/214)
* Eth/solidity: add docs for solc path override [#213](https://github.com/q9f/eth.rb/pull/213)
* Manually overwrite solc path [#212](https://github.com/q9f/eth.rb/pull/212)
* Abi.decoder handles arrays of string and bytes [#207](https://github.com/q9f/eth.rb/pull/207)
* Eth/util: fix compressed public key to address in [#206](https://github.com/q9f/eth.rb/pull/206)
* Eth/api: update execution apis to latest spec [#204](https://github.com/q9f/eth.rb/pull/204)
* Eth/abi: split abi class into encoder and decoder [#203](https://github.com/q9f/eth.rb/pull/203)
* Eth/client: deduplicate code [#202](https://github.com/q9f/eth.rb/pull/202)
* Eth/client: rewrite send to send_request [#201](https://github.com/q9f/eth.rb/pull/201)
* Docs: update changelog for 0.5.10 [#200](https://github.com/q9f/eth.rb/pull/200)
* Tested with Ruby 3.2 [#199](https://github.com/q9f/eth.rb/pull/199)

## [0.5.10]
### Added
* Eth/client: add transfer_erc20 function [#197](https://github.com/q9f/eth.rb/pull/197)
* Eth/client: add resolve_ens function [#192](https://github.com/q9f/eth.rb/pull/192)

### Changed
* Eth/ens: restore docs for normalize [#198](https://github.com/q9f/eth.rb/pull/198)
* Docs: update readme [#195](https://github.com/q9f/eth.rb/pull/195)
* Eth/contract: ensure address arrays support [#194](https://github.com/q9f/eth.rb/pull/194)
* Eth/client: do not allow accessing local accounts on remote connections [#193](https://github.com/q9f/eth.rb/pull/193)
* Eth/client: correctly select functions [#191](https://github.com/q9f/eth.rb/pull/191)
* Docs: create security policy [#190](https://github.com/q9f/eth.rb/pull/190)
* Docs: add contribution guidelines [#189](https://github.com/q9f/eth.rb/pull/189)
* Docs: add coc [#188](https://github.com/q9f/eth.rb/pull/188)
* Docs: update changelog for 0.5.9 [#187](https://github.com/q9f/eth.rb/pull/187)

## [0.5.9]
### Added
* Eth/abi: dynamic struct encoding [#135](https://github.com/q9f/eth.rb/pull/135) [#185](https://github.com/q9f/eth.rb/pull/185)
* Eth/client: support camel case (convert before sending the tx) [#172](https://github.com/q9f/eth.rb/pull/172)
* Eth/client: add `tx_succeeded?` [#173](https://github.com/q9f/eth.rb/pull/173)

### Changed
* Eth/client: raise an error if a contract interaction reverts [#186](https://github.com/q9f/eth.rb/pull/186)
* Eth/client: dup params to prevent marshalling on client obj [#184](https://github.com/q9f/eth.rb/pull/184)
* Eth/client: add test for tx_succeeded? [#183](https://github.com/q9f/eth.rb/pull/183)
* Eth: rename functions prefixed with is_ [#182](https://github.com/q9f/eth.rb/pull/182)
* Eth/chain: update available chains [#181](https://github.com/q9f/eth.rb/pull/181)
* Docs: update changelog for 0.5.8 [#180](https://github.com/q9f/eth.rb/pull/180)
* Eth: happy new 2023 [#179](https://github.com/q9f/eth.rb/pull/179)
* Docs: fix readme workflow badge [#178](https://github.com/q9f/eth.rb/pull/178)
* Solidity: sanitize the contract path before compiling [#176](https://github.com/q9f/eth.rb/pull/176)
* Ci: add libyaml on ubuntu [#175](https://github.com/q9f/eth.rb/pull/175)

## [0.5.8]
### Added
* Client: ability to manual set nonce of tx for transfer, deploy, transact methods was added. [#169](https://github.com/q9f/eth.rb/pull/169)
* Client: ability for call contract methods with specific transaction value was added [#168](https://github.com/q9f/eth.rb/pull/168)
* Client: add ENS resolve support [#150](https://github.com/q9f/eth.rb/pull/150)

### Changed
* Client: satisfy yard docs for transfer kwargs [#170](https://github.com/q9f/eth.rb/pull/170)
* Client: remove invalid parameters from call_raw method [#166](https://github.com/q9f/eth.rb/pull/166)
* Gem: bump required ruby version to 3 [#165](https://github.com/q9f/eth.rb/pull/165)
* Build(deps): bump JamesIves/github-pages-deploy-action from 4.4.0 to 4.4.1 [#162](https://github.com/q9f/eth.rb/pull/162)
* Gem: bump version to 0.5.8 [#161](https://github.com/q9f/eth.rb/pull/161)
* Docs: update changelog [#160](https://github.com/q9f/eth.rb/pull/160)

## [0.5.7]
### Added
* Eth/client: add http basic support auth ([#151](https://github.com/q9f/eth.rb/pull/151))
* Chore: add polygon chain test case ([#146](https://github.com/q9f/eth.rb/pull/146))

### Changed
* Docs: add readme header for yard ([#159](https://github.com/q9f/eth.rb/pull/159))
* Eth/client: fix api documentation ([#158](https://github.com/q9f/eth.rb/pull/158))
* Eth/client: update default fees ([#157](https://github.com/q9f/eth.rb/pull/157))
* Docs: move readme usage to wiki ([#156](https://github.com/q9f/eth.rb/pull/156))
* Eth/signature: fix allowing ledger v values of 0 ([#155](https://github.com/q9f/eth.rb/pull/155))
* Eth/client: rename http basic to http auth ([#154](https://github.com/q9f/eth.rb/pull/154))
* Fix Eth:Tx.decode for transaction with s length < 64 chars ([#148](https://github.com/q9f/eth.rb/pull/148))
* Build(deps): bump JamesIves/github-pages-deploy-action from 4.3.4 to 4.4.0 ([#140](https://github.com/q9f/eth.rb/pull/140))
* Fixed to return uint256[] correctly when passed as type ([#147](https://github.com/q9f/eth.rb/pull/147))
* Build(deps): bump JamesIves/github-pages-deploy-action from 4.3.3 to 4.3.4 ([#133](https://github.com/q9f/eth.rb/pull/133))
* Docs: update CHANGELOG ([#132](https://github.com/q9f/eth.rb/pull/132))
* Gem: bump version to 0.5.7 ([#131](https://github.com/q9f/eth.rb/pull/131))

## [0.5.6]
### Added
- Eth/client: Add gas limit override option for contract deployments ([#128](https://github.com/q9f/eth.rb/pull/128))
- Eth/abi: support dynamic array encoding ([#122](https://github.com/q9f/eth.rb/pull/122))

### Changed
- Eth/client: Include contract constructor args when estimating intrinsic gas ([#111](https://github.com/q9f/eth.rb/pull/111))
- Eth/abi: allow parsing numerics from string inputs ([#112](https://github.com/q9f/eth.rb/pull/112))
- Eth/signature: fix prefix_message for multibyte characters ([#120](https://github.com/q9f/eth.rb/pull/120))
- Eth/abi: raise error if numeric comes as string ([#114](https://github.com/q9f/eth.rb/pull/114))
- Gem: bump version to 0.5.6 ([#130](https://github.com/q9f/eth.rb/pull/130))

## [0.5.5]
### Added
- Eth/contract: Add missing def_delegator for constructor_inputs ([#96](https://github.com/q9f/eth.rb/pull/96))
- Eth/client: Enable passing in constructor params to deploy ([#106](https://github.com/q9f/eth.rb/pull/106))
- Eth/chain: add matic/mumbai ([#107](https://github.com/q9f/eth.rb/pull/107))

### Changed
- Gem: bump version to 0.5.5 ([#89](https://github.com/q9f/eth.rb/pull/89))
- Docs: update changelog for 0.5.4 ([#90](https://github.com/q9f/eth.rb/pull/90))
- Ci: add weekly dependency checks ([#91](https://github.com/q9f/eth.rb/pull/91))
- Build(deps): bump github/codeql-action from 1 to 2 ([#92](https://github.com/q9f/eth.rb/pull/92))
- Build(deps): bump actions/checkout from 2 to 3 ([#93](https://github.com/q9f/eth.rb/pull/93))
- Build(deps): bump JamesIves/github-pages-deploy-action from 4.1.7 to 4.3.3 ([#94](https://github.com/q9f/eth.rb/pull/94))
- Eth/abi: fix handling of hex values for byte strings ([#100](https://github.com/q9f/eth.rb/pull/100))
- Eth/abi: add a testcase for handling hex and bin strings ([#101](https://github.com/q9f/eth.rb/pull/101))
- Eth/abi: Fix Eth::Abi::DecodingError in call method ([#105](https://github.com/q9f/eth.rb/pull/105))
- Eth: some docs and cleanups ([#108](https://github.com/q9f/eth.rb/pull/108))

## [0.5.4]
### Added
- Eth/client: method for eip-1271 ([#80](https://github.com/q9f/eth.rb/pull/80))

### Changed
- Docs: update changelog ([#77](https://github.com/q9f/eth.rb/pull/77))
- Gem: bump version to 0.5.4 ([#78](https://github.com/q9f/eth.rb/pull/78))
- Ci: bump ruby version to 3.1 on ci ([#79](https://github.com/q9f/eth.rb/pull/79))
- Fix typos ([#81](https://github.com/q9f/eth.rb/pull/81))
- Eth/contract: allow creating from file, abi, bin ([#83](https://github.com/q9f/eth.rb/pull/83))
- Eth/client: fix account requirement for client.call() ([#85](https://github.com/q9f/eth.rb/pull/85))
- Add dependency support for openssl 2.2 and greater, including 3.x ([#88](https://github.com/q9f/eth.rb/pull/88))

## [0.5.3]
### Added
- Smart contract support ([#68](https://github.com/q9f/eth.rb/pull/68))

### Changed
- Eth/abi: decode event log ([#69](https://github.com/q9f/eth.rb/pull/69))
- Gem: bump version ([#70](https://github.com/q9f/eth.rb/pull/70))
- Eth/abi/event: batch log decoder ([#71](https://github.com/q9f/eth.rb/pull/71))

## [0.5.2]
### Added
- Eth/solidity: add solidity compiler bindings ([#66](https://github.com/q9f/eth.rb/pull/66))

### Changed
- Eth: remove duplicated code ([#62](https://github.com/q9f/eth.rb/pull/62))
- Ci: allow coverage to drop to 99% without failing ([#63](https://github.com/q9f/eth.rb/pull/63))
- Docs: update readme ([#64](https://github.com/q9f/eth.rb/pull/64))
- Docs: add wiki to readme ([#65](https://github.com/q9f/eth.rb/pull/65))

## [0.5.1]
### Added
- Add eth::rlp module ([#52](https://github.com/q9f/eth.rb/pull/52))
- Eth/client: implement http/ipc ([#37](https://github.com/q9f/eth.rb/pull/37))

### Changed
- Docs: update changelog ([#61](https://github.com/q9f/eth.rb/pull/61))
- Eth/chain: add sepolia chain id; docs ([#60](https://github.com/q9f/eth.rb/pull/60))
- Eth/rlp: cleanup ([#59](https://github.com/q9f/eth.rb/pull/59))
- Eth/tx: properly serialize signatures ([#58](https://github.com/q9f/eth.rb/pull/58))
- Eth/client: fix legacy transfer ([#57](https://github.com/q9f/eth.rb/pull/57))
- Gem: relax openssl requirement ([#56](https://github.com/q9f/eth.rb/pull/56))
- Docs: update changelog ([#53](https://github.com/q9f/eth.rb/pull/53))
- Spec: add upstream test fixtures for keystore ([#50](https://github.com/q9f/eth.rb/pull/50))

## [0.5.0]
### Added
- Eth/tx: create legacy, type-1, and type-2 transactions [#33](https://github.com/q9f/eth.rb/pull/33)
- Signature: implement eip 712 typed structured data signing [#27](https://github.com/q9f/eth.rb/pull/27)
- Lib: import ABI to eth/abi [#29](https://github.com/q9f/eth.rb/pull/29)
- Eth/chains: implement eip 155 for replay protection [#20](https://github.com/q9f/eth.rb/pull/20)

### Changed
- Docs: update readme with features [#49](https://github.com/q9f/eth.rb/pull/49)
- Eth/tx: add method to estimate intrinsic gas costs [#48](https://github.com/q9f/eth.rb/pull/48)
- Eth/key: allow chain_id empty for signing messages/data [#47](https://github.com/q9f/eth.rb/pull/47)
- Gem: prepare for release [#46](https://github.com/q9f/eth.rb/pull/46)
- Eth/sig: allow v values > 0xff, fix #30 [#43](https://github.com/q9f/eth.rb/pull/43)
- Eth/abi: refactor for maintainability [#42](https://github.com/q9f/eth.rb/pull/42)
- Docs: improve readme [#41](https://github.com/q9f/eth.rb/pull/41)
- Lib: improve error handling [#39](https://github.com/q9f/eth.rb/pull/39)
- Docs: update readme for tx and keys [#40](https://github.com/q9f/eth.rb/pull/40)
- Implement encrypt/decrypt [#22](https://github.com/q9f/eth.rb/pull/22)
- Gem: clean up some docs and scripts [#32](https://github.com/q9f/eth.rb/pull/32)
- Rename util and chain to singular [#26](https://github.com/q9f/eth.rb/pull/26)
- Docs: add some examples to readme [#25](https://github.com/q9f/eth.rb/pull/25)
- Key/signature: personal sign and verify [#24](https://github.com/q9f/eth.rb/pull/24)
- Ci: only run coverage on CI [#23](https://github.com/q9f/eth.rb/pull/23)
- Lib/signature: implement personal_recover (eip 191 [#21](https://github.com/q9f/eth.rb/pull/21)
- Eth/util: public_key_to_address should return an eth::address [#19](https://github.com/q9f/eth.rb/pull/19)
- Ci: add docs workflow [#18](https://github.com/q9f/eth.rb/pull/18)
- Address class implementation and tests [#13](https://github.com/q9f/eth.rb/pull/13)
- Spec: improve util tests [#12](https://github.com/q9f/eth.rb/pull/12)
- Spec: improve key tests [#11](https://github.com/q9f/eth.rb/pull/11)
- Gems: bump keccak and secp256k1 [#10](https://github.com/q9f/eth.rb/pull/10)
- Docs: add code climate badge [#8](https://github.com/q9f/eth.rb/pull/8)
- Ci: enable codecov [#7](https://github.com/q9f/eth.rb/pull/7)
- Docs: add AUTHORS file [#6](https://github.com/q9f/eth.rb/pull/6)
- Lib: implement Eth::Key class [#4](https://github.com/q9f/eth.rb/pull/4)
- Ci: add nightly schedule [#2](https://github.com/q9f/eth.rb/pull/2)
- Reset gem to point blank [#1](https://github.com/q9f/eth.rb/pull/1)

## [0.4.18]
### Changed
- CI: add yard doc and rufo workflows [se3000/ruby-eth#75](https://github.com/se3000/ruby-eth/pull/75)
- Gem: run rufo [se3000/ruby-eth#74](https://github.com/se3000/ruby-eth/pull/74)
- Gem: dependencies [se3000/ruby-eth#73](https://github.com/se3000/ruby-eth/pull/73)
- Lib: fix compatibility with libressl (macos) and openssl 1.1.1k [se3000/ruby-eth#66](https://github.com/se3000/ruby-eth/pull/66)

## [0.4.17]
### Changed
- Gems: bump version to 0.4.17 [se3000/ruby-eth#70](https://github.com/se3000/ruby-eth/pull/70)
- Gems: bump keccak to 1.3.0 [se3000/ruby-eth#69](https://github.com/se3000/ruby-eth/pull/69)

## [0.4.16]
### Changed
- Docs: update changelog [se3000/ruby-eth#65](https://github.com/se3000/ruby-eth/pull/65)
- Gems: bump version to 0.4.16 [se3000/ruby-eth#65](https://github.com/se3000/ruby-eth/pull/65)
- License: update copyright notice [se3000/ruby-eth#64](https://github.com/se3000/ruby-eth/pull/64)
- Docs: add badges to readme [se3000/ruby-eth#64](https://github.com/se3000/ruby-eth/pull/64)
- Git: deprecating master [se3000/ruby-eth#63](https://github.com/se3000/ruby-eth/pull/63)
- CI: replace travis with github actions [se3000/ruby-eth#62](https://github.com/se3000/ruby-eth/pull/62)
- Gems: replace digest-sha3-patched with keccak [se3000/ruby-eth#58](https://github.com/se3000/ruby-eth/pull/58)

## [0.4.13], [0.4.14], [0.4.15]
_Released as [`eth-patched`](https://github.com/q9f/ruby-eth) from a different source tree._

## [0.4.12]
### Changed
- Bump rake version because of security vulnerability

## [0.4.11]
### Added
- Support for recovering signatures with a V value below 27 (like from Ledger hardware wallets)

## [0.4.10]
### Changed
- Use updated sha3 dependency
- Improved OpenSSL support

### Changed
- Changed Eth::Configuration.default_chain_id back to .chain_id for dependent libraries.

## [0.4.9]
### Changed
- [escoffon](https://github.com/escoffon) added support for chain IDs larger than 120.

## [0.4.8]
### Added
- [@buhrmi](https://github.com/buhrmi) added Eth::Key#personal_sign.
- [@buhrmi](https://github.com/buhrmi) added Eth::Key#personal_recover.

## [0.4.7]
### Changed
- Updated MoneyTree dependency.

## [0.4.6]
### Added
- Support scrypt private key decryption

## [0.4.5]
### Changed
- Further improve Open SSL configurability

## [0.4.4]
### Changed
- Support old versions of SSL to help avoid preious breaking changes

## [0.4.3]
### Added
- Eth::Key::Encrypter class to handle encrypting keys.
- Eth::Key.encrypt as a nice wrapper around Encrypter class.
- Eth::Key::Decrypter class to handle encrypting keys.
- Eth::Key.decrypt as a nice wrapper around Decrypter class.

## [0.4.2]
### Added
- Address#valid? to validate EIP55 checksums.
- Address#checksummed to generate EIP55 checksums.
- Utils.valid_address? to easily validate EIP55 checksums.
- Utils.format_address to easily convert an address to EIP55 checksummed.

### Changed
- Dependencies no longer include Ethereum::Base. Eth now implements those helpers directly and includes ffi, digest-sha3, and rlp directly.


## [0.4.1]
### Changed
- Tx#hash includes the '0x' hex prefix.

## [0.4.0]
### Added
- Tx#data_bin returns the data field of a transaction in binary.
- Tx#data_hex returns the data field of a transaction as a hexadecimal string.
- Tx#id is an alias of Tx#hash

### Changed
- Tx#data is configurable to return either hex or binary: `config.tx_data_hex = true`.
- Tx#hex includes the '0x' hex prefix.
- Key#address getter is prepended by '0x'.
- Extract public key to address method into Utils.public_key_to_address.
- Tx#from returns an address instead of a public key.
- Chain ID is updated to the later version of the spec.


================================================
FILE: CODE_OF_CONDUCT.md
================================================

# Code of Conduct

## Our Pledge

We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.

We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.

## Our Standards

Examples of behavior that contributes to a positive environment for our
community include:

* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
  and learning from the experience
* Focusing on what is best not just for us as individuals, but for the overall
  community

Examples of unacceptable behavior include:

* The use of sexualized language or imagery, and sexual attention or advances of
  any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email address,
  without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
  professional setting

## Enforcement Responsibilities

Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.

Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.

## Scope

This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
<github@q9f.cc>.
All complaints will be reviewed and investigated promptly and fairly.

All community leaders are obligated to respect the privacy and security of the
reporter of any incident.

## Enforcement Guidelines

Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:

### 1. Correction

**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.

**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.

### 2. Warning

**Community Impact**: A violation through a single incident or series of
actions.

**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.

### 3. Temporary Ban

**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.

**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.

### 4. Permanent Ban

**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.

**Consequence**: A permanent ban from any sort of public interaction within the
community.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org),
version 2.1, available at [v2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct.html).
Community Impact Guidelines were inspired by Mozilla's code of conduct enforcement ladder.


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to Ruby Ethereum

Everyone is welcome to contribute to the Ruby Ethereum gem. It is
more than six years old and had seen many maintainers come and go.

Current maintainers:
* [@q9f](https://github.com/q9f)
* [@kurotaky](https://github.com/kurotaky)

### Workflow

To propose a change, fix, or new feature, create an issue or comment
on an existing issue to see if anyone else has an opinion on it or is
eventually already working on it

The general workflow looks roughly like this:

1. Discuss it
2. Fork it
3. Improve it
4. Test it
5. Document it
6. Submit it

### Linting

We use the Ruby formatter `rufo` to ensure consistent formatting across
the code base.
* <https://github.com/ruby-formatter/rufo>

Simply run `rufo .` before comitting your changes.

### Testing

We use behaviour-driven development and this codebase is at least 100%
unit tested. We use RSpec to run the spec tests.
* <https://rspec.info>

The full Ethereum test-suite is available in `fixtures/ethereum/tests`.
Run `git submodule update --init --recursive` to fetch it.
* <https://github.com/ethereum/tests>

If your tests are failing make sure you pulled the ethereum/tests 
submodule and run a local geth node in background with
`geth --dev --http --ipcpath /tmp/geth.ipc` as we are running some tests
against a local live node.

Other static test data is available in `fixtures/`

### Documentation

We use the Ruby documentation tool Yard.
* <https://yardoc.org>

The code base is 100% API documented.
* <https://q9f.github.io/eth.rb>

More involved documentation, tutorials, and usage examples should go
into the wiki.
* <https://github.com/q9f/eth.rb/wiki>



================================================
FILE: Gemfile
================================================
# frozen_string_literal: true

source "https://rubygems.org"

group :test, :development do
  gem "bundler", ">= 2.4"
  gem "pry", "~> 0.15"
  gem "rake", "~> 13.2"
  gem "rdoc", "~> 6.13"
  gem "rspec", "~> 3.13"
  gem "rufo", "~> 0.18"
  gem "simplecov", "~> 0.22"
  gem "simplecov-cobertura", "~> 3.0"
  gem "yard", "~> 0.9"
end

gemspec


================================================
FILE: LICENSE.txt
================================================

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright (c) 2016-2025 The Ruby-Eth Contributors

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================
<!--
# @markup markdown
# @title Ethereum for Ruby
# @author Afri Schoedon
-->

# Ethereum for Ruby

[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/q9f/eth.rb/spec.yml?branch=main)](https://github.com/q9f/eth.rb/actions)
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/q9f/eth.rb)](https://github.com/q9f/eth.rb/releases)
[![Gem](https://img.shields.io/gem/v/eth)](https://rubygems.org/gems/eth)
[![Gem](https://img.shields.io/gem/dt/eth)](https://rubygems.org/gems/eth)
[![codecov](https://codecov.io/gh/q9f/eth.rb/branch/main/graph/badge.svg?token=IK7USBPBZY)](https://codecov.io/gh/q9f/eth.rb)
[![Top Language](https://img.shields.io/github/languages/top/q9f/eth.rb?color=red)](https://github.com/q9f/eth.rb/pulse)
[![Yard Doc API](https://img.shields.io/badge/documentation-API-blue)](https://q9f.github.io/eth.rb)
[![Usage Wiki](https://img.shields.io/badge/usage-WIKI-blue)](https://github.com/q9f/eth.rb/wiki)
[![Open-Source License](https://img.shields.io/github/license/q9f/eth.rb)](LICENSE.txt)
[![Contributions Welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/q9f/eth.rb/issues)

A straightforward library to build, sign, and broadcast Ethereum transactions. It allows the separation of key and node management. Sign transactions and handle keys anywhere you can run Ruby and broadcast transactions through any local or remote node. Sign messages and recover signatures for authentication.

What you get:
- [x] Secp256k1 Key-Pairs and Encrypted Ethereum Key-Stores (JSON)
- [x] EIP-20 Token Transfers (ERC20)
- [x] EIP-55 Checksummed Ethereum Addresses
- [x] EIP-137 Ethereum Domain Name Service (ENS)
- [x] EIP-155 Replay protection with Chain IDs (with presets)
- [x] EIP-191 Ethereum Signed Messages (with prefix and type)
- [x] EIP-712 Ethereum Signed Type Data
- [x] EIP-1271 Smart-Contract Authentification
- [x] EIP-1559 Ethereum Type-2 Transactions (with priority fee and max gas fee)
- [x] EIP-2028 Call-data intrinsic gas cost estimates (plus access lists)
- [x] EIP-2718 Ethereum Transaction Envelopes (and types)
- [x] EIP-2930 Ethereum Type-1 Transactions (with access lists)
- [x] EIP-4844 Ethereum Type-3 Transactions (with shard blobs, up to 9 blobs per block)
- [x] EIP-7702 Ethereum Type-4 Transactions (with authorization lists)
- [x] ABI-Encoder and Decoder (including type parser)
- [x] Packed ABI-Encoder for Solidity smart contracts
- [x] RLP-Encoder and Decoder (including sedes)
- [x] RPC-Client (IPC/HTTP/WS) for Execution-Layer APIs
- [x] Solidity bindings (compile contracts from Ruby)
- [x] Full smart-contract support (deploy, transact, and call)
- [x] ERC-6093 custom Solidity errors

## Installation
Add this line to your application's Gemfile:

```ruby
gem "eth"
```

Or install it yourself as:

```shell
gem install eth
```

## Usage
Check out the
[![Yard API Docs](https://img.shields.io/badge/documentation-API-blue)](https://q9f.github.io/eth.rb)
and the
[![Usage Wiki](https://img.shields.io/badge/usage-WIKI-blue)](https://github.com/q9f/eth.rb/wiki)
for all the details and example snippets.

## Documentation
The documentation can be found at: https://q9f.github.io/eth.rb

For any specific version, docs can be generated by `yard`:

```shell
gem install bundler rdoc yard
git checkout $VERSION
yard doc
```

The goal is to have 100% API documentation available.

## Testing
The test suite expects working local HTTP, WS, and IPC endpoints with a prefunded developer account, e.g.:

```shell
geth --dev --http --ws --ipcpath /tmp/geth.ipc &
```

To run tests, simply use `rspec`. Note, that the Ethereum test fixtures are also required.

```shell
git submodule update --init --recursive
bundle install
rspec
```

The goal is to have 100% unit-test coverage for all code inside this gem.

## Contributing
Pull requests are welcome! To contribute, please consider the following:
* Code should be fully documented. Run `yard doc` and make sure it does not yield any warnings or undocumented sets.
* Code should be fully covered by tests. Run `rspec` to make sure all tests pass. The CI has an integration that will assist you to identify uncovered lines of code and get coverage up to 100%.
* Code should be formatted properly. Try to eliminate the most common issues such as trailing white-spaces or duplicate new-lines. Usage of the `rufo` gem is recommended.
* Submit pull requests, questions, or issues to Github: <https://github.com/q9f/eth.rb>

## License and Credits
The `eth` gem is licensed under the conditions of [Apache 2.0](./LICENSE.txt). Please see [AUTHORS](./AUTHORS.txt) for contributors and copyright notices.

This gem is a complete rewrite of the old `eth` gem by Steve Ellis.
* <https://github.com/se3000/ruby-eth> (MIT)

It is not only a rewrite of the `eth` gem but also a partial merge of the `ethereum` gem by Marek Kirejczyk and Yuta Kurotaki.
* <https://github.com/EthWorks/ethereum.rb> (MIT)

This gem also includes a revised version of the ABI gem by Jan Xie and Zhang Yaning.
* <https://github.com/cryptape/ruby-ethereum-abi> (MIT)

It also contains a condensed version of the RLP gem by Jan Xie and Zhang Yaning.
* <https://github.com/cryptape/ruby-rlp> (MIT)


================================================
FILE: Rakefile
================================================
require "bundler/gem_tasks"
require "rspec/core/rake_task"

RSpec::Core::RakeTask.new(:spec)

task :default => :spec


================================================
FILE: SECURITY.md
================================================
# Security Policy

## Supported Versions

Ruby Ethereum 0.5.x is a complete rewrite of the old `eth` 0.4.x gem.
It also contains modules from `abi`, `rlp` and the `ethereum` gem.

None of these gems are maintained anymore except for `eth` 0.5.0 and
later.

| Gem            | Version | Supported          |
| -------------- | ------- | ------------------ |
| `eth`          | >= 0.5  | :white_check_mark: |
| `eth`          | <  0.5  | :x:                |
| `ethereum`     | _any_   | :x:                |
| `ethereum-abi` | _any_   | :x:                |
| `rlp`          | _any_   | :x:                |

## Reporting a Vulnerability

Please report your findings to <security@q9f.cc>. Do not create a
Github issue!

You can expect an answer within 48 hours.


================================================
FILE: abi/ens_registry.json
================================================
[
  {
    "inputs":[
      {
        "internalType":"contract ENS",
        "name":"_old",
        "type":"address"
      }
    ],
    "payable":false,
    "stateMutability":"nonpayable",
    "type":"constructor"
  },
  {
    "anonymous":false,
    "inputs":[
      {
        "indexed":true,
        "internalType":"address",
        "name":"owner",
        "type":"address"
      },
      {
        "indexed":true,
        "internalType":"address",
        "name":"operator",
        "type":"address"
      },
      {
        "indexed":false,
        "internalType":"bool",
        "name":"approved",
        "type":"bool"
      }
    ],
    "name":"ApprovalForAll",
    "type":"event"
  },
  {
    "anonymous":false,
    "inputs":[
      {
        "indexed":true,
        "internalType":"bytes32",
        "name":"node",
        "type":"bytes32"
      },
      {
        "indexed":true,
        "internalType":"bytes32",
        "name":"label",
        "type":"bytes32"
      },
      {
        "indexed":false,
        "internalType":"address",
        "name":"owner",
        "type":"address"
      }
    ],
    "name":"NewOwner",
    "type":"event"
  },
  {
    "anonymous":false,
    "inputs":[
      {
        "indexed":true,
        "internalType":"bytes32",
        "name":"node",
        "type":"bytes32"
      },
      {
        "indexed":false,
        "internalType":"address",
        "name":"resolver",
        "type":"address"
      }
    ],
    "name":"NewResolver",
    "type":"event"
  },
  {
    "anonymous":false,
    "inputs":[
      {
        "indexed":true,
        "internalType":"bytes32",
        "name":"node",
        "type":"bytes32"
      },
      {
        "indexed":false,
        "internalType":"uint64",
        "name":"ttl",
        "type":"uint64"
      }
    ],
    "name":"NewTTL",
    "type":"event"
  },
  {
    "anonymous":false,
    "inputs":[
      {
        "indexed":true,
        "internalType":"bytes32",
        "name":"node",
        "type":"bytes32"
      },
      {
        "indexed":false,
        "internalType":"address",
        "name":"owner",
        "type":"address"
      }
    ],
    "name":"Transfer",
    "type":"event"
  },
  {
    "constant":true,
    "inputs":[
      {
        "internalType":"address",
        "name":"owner",
        "type":"address"
      },
      {
        "internalType":"address",
        "name":"operator",
        "type":"address"
      }
    ],
    "name":"isApprovedForAll",
    "outputs":[
      {
        "internalType":"bool",
        "name":"",
        "type":"bool"
      }
    ],
    "payable":false,
    "stateMutability":"view",
    "type":"function"
  },
  {
    "constant":true,
    "inputs":[

    ],
    "name":"old",
    "outputs":[
      {
        "internalType":"contract ENS",
        "name":"",
        "type":"address"
      }
    ],
    "payable":false,
    "stateMutability":"view",
    "type":"function"
  },
  {
    "constant":true,
    "inputs":[
      {
        "internalType":"bytes32",
        "name":"node",
        "type":"bytes32"
      }
    ],
    "name":"owner",
    "outputs":[
      {
        "internalType":"address",
        "name":"",
        "type":"address"
      }
    ],
    "payable":false,
    "stateMutability":"view",
    "type":"function"
  },
  {
    "constant":true,
    "inputs":[
      {
        "internalType":"bytes32",
        "name":"node",
        "type":"bytes32"
      }
    ],
    "name":"recordExists",
    "outputs":[
      {
        "internalType":"bool",
        "name":"",
        "type":"bool"
      }
    ],
    "payable":false,
    "stateMutability":"view",
    "type":"function"
  },
  {
    "constant":true,
    "inputs":[
      {
        "internalType":"bytes32",
        "name":"node",
        "type":"bytes32"
      }
    ],
    "name":"resolver",
    "outputs":[
      {
        "internalType":"address",
        "name":"",
        "type":"address"
      }
    ],
    "payable":false,
    "stateMutability":"view",
    "type":"function"
  },
  {
    "constant":false,
    "inputs":[
      {
        "internalType":"address",
        "name":"operator",
        "type":"address"
      },
      {
        "internalType":"bool",
        "name":"approved",
        "type":"bool"
      }
    ],
    "name":"setApprovalForAll",
    "outputs":[

    ],
    "payable":false,
    "stateMutability":"nonpayable",
    "type":"function"
  },
  {
    "constant":false,
    "inputs":[
      {
        "internalType":"bytes32",
        "name":"node",
        "type":"bytes32"
      },
      {
        "internalType":"address",
        "name":"owner",
        "type":"address"
      }
    ],
    "name":"setOwner",
    "outputs":[

    ],
    "payable":false,
    "stateMutability":"nonpayable",
    "type":"function"
  },
  {
    "constant":false,
    "inputs":[
      {
        "internalType":"bytes32",
        "name":"node",
        "type":"bytes32"
      },
      {
        "internalType":"address",
        "name":"owner",
        "type":"address"
      },
      {
        "internalType":"address",
        "name":"resolver",
        "type":"address"
      },
      {
        "internalType":"uint64",
        "name":"ttl",
        "type":"uint64"
      }
    ],
    "name":"setRecord",
    "outputs":[

    ],
    "payable":false,
    "stateMutability":"nonpayable",
    "type":"function"
  },
  {
    "constant":false,
    "inputs":[
      {
        "internalType":"bytes32",
        "name":"node",
        "type":"bytes32"
      },
      {
        "internalType":"address",
        "name":"resolver",
        "type":"address"
      }
    ],
    "name":"setResolver",
    "outputs":[

    ],
    "payable":false,
    "stateMutability":"nonpayable",
    "type":"function"
  },
  {
    "constant":false,
    "inputs":[
      {
        "internalType":"bytes32",
        "name":"node",
        "type":"bytes32"
      },
      {
        "internalType":"bytes32",
        "name":"label",
        "type":"bytes32"
      },
      {
        "internalType":"address",
        "name":"owner",
        "type":"address"
      }
    ],
    "name":"setSubnodeOwner",
    "outputs":[
      {
        "internalType":"bytes32",
        "name":"",
        "type":"bytes32"
      }
    ],
    "payable":false,
    "stateMutability":"nonpayable",
    "type":"function"
  },
  {
    "constant":false,
    "inputs":[
      {
        "internalType":"bytes32",
        "name":"node",
        "type":"bytes32"
      },
      {
        "internalType":"bytes32",
        "name":"label",
        "type":"bytes32"
      },
      {
        "internalType":"address",
        "name":"owner",
        "type":"address"
      },
      {
        "internalType":"address",
        "name":"resolver",
        "type":"address"
      },
      {
        "internalType":"uint64",
        "name":"ttl",
        "type":"uint64"
      }
    ],
    "name":"setSubnodeRecord",
    "outputs":[

    ],
    "payable":false,
    "stateMutability":"nonpayable",
    "type":"function"
  },
  {
    "constant":false,
    "inputs":[
      {
        "internalType":"bytes32",
        "name":"node",
        "type":"bytes32"
      },
      {
        "internalType":"uint64",
        "name":"ttl",
        "type":"uint64"
      }
    ],
    "name":"setTTL",
    "outputs":[

    ],
    "payable":false,
    "stateMutability":"nonpayable",
    "type":"function"
  },
  {
    "constant":true,
    "inputs":[
      {
        "internalType":"bytes32",
        "name":"node",
        "type":"bytes32"
      }
    ],
    "name":"ttl",
    "outputs":[
      {
        "internalType":"uint64",
        "name":"",
        "type":"uint64"
      }
    ],
    "payable":false,
    "stateMutability":"view",
    "type":"function"
  }
]


================================================
FILE: abi/ens_resolver.json
================================================
[
    {
      "inputs":[
        {
          "internalType":"contract ENS",
          "name":"_ens",
          "type":"address"
        }
      ],
      "payable":false,
      "stateMutability":"nonpayable",
      "type":"constructor"
    },
    {
      "anonymous":false,
      "inputs":[
        {
          "indexed":true,
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        },
        {
          "indexed":true,
          "internalType":"uint256",
          "name":"contentType",
          "type":"uint256"
        }
      ],
      "name":"ABIChanged",
      "type":"event"
    },
    {
      "anonymous":false,
      "inputs":[
        {
          "indexed":true,
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        },
        {
          "indexed":false,
          "internalType":"address",
          "name":"a",
          "type":"address"
        }
      ],
      "name":"AddrChanged",
      "type":"event"
    },
    {
      "anonymous":false,
      "inputs":[
        {
          "indexed":true,
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        },
        {
          "indexed":false,
          "internalType":"uint256",
          "name":"coinType",
          "type":"uint256"
        },
        {
          "indexed":false,
          "internalType":"bytes",
          "name":"newAddress",
          "type":"bytes"
        }
      ],
      "name":"AddressChanged",
      "type":"event"
    },
    {
      "anonymous":false,
      "inputs":[
        {
          "indexed":true,
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        },
        {
          "indexed":true,
          "internalType":"address",
          "name":"owner",
          "type":"address"
        },
        {
          "indexed":true,
          "internalType":"address",
          "name":"target",
          "type":"address"
        },
        {
          "indexed":false,
          "internalType":"bool",
          "name":"isAuthorised",
          "type":"bool"
        }
      ],
      "name":"AuthorisationChanged",
      "type":"event"
    },
    {
      "anonymous":false,
      "inputs":[
        {
          "indexed":true,
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        },
        {
          "indexed":false,
          "internalType":"bytes",
          "name":"hash",
          "type":"bytes"
        }
      ],
      "name":"ContenthashChanged",
      "type":"event"
    },
    {
      "anonymous":false,
      "inputs":[
        {
          "indexed":true,
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        },
        {
          "indexed":false,
          "internalType":"bytes",
          "name":"name",
          "type":"bytes"
        },
        {
          "indexed":false,
          "internalType":"uint16",
          "name":"resource",
          "type":"uint16"
        },
        {
          "indexed":false,
          "internalType":"bytes",
          "name":"record",
          "type":"bytes"
        }
      ],
      "name":"DNSRecordChanged",
      "type":"event"
    },
    {
      "anonymous":false,
      "inputs":[
        {
          "indexed":true,
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        },
        {
          "indexed":false,
          "internalType":"bytes",
          "name":"name",
          "type":"bytes"
        },
        {
          "indexed":false,
          "internalType":"uint16",
          "name":"resource",
          "type":"uint16"
        }
      ],
      "name":"DNSRecordDeleted",
      "type":"event"
    },
    {
      "anonymous":false,
      "inputs":[
        {
          "indexed":true,
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        }
      ],
      "name":"DNSZoneCleared",
      "type":"event"
    },
    {
      "anonymous":false,
      "inputs":[
        {
          "indexed":true,
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        },
        {
          "indexed":true,
          "internalType":"bytes4",
          "name":"interfaceID",
          "type":"bytes4"
        },
        {
          "indexed":false,
          "internalType":"address",
          "name":"implementer",
          "type":"address"
        }
      ],
      "name":"InterfaceChanged",
      "type":"event"
    },
    {
      "anonymous":false,
      "inputs":[
        {
          "indexed":true,
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        },
        {
          "indexed":false,
          "internalType":"string",
          "name":"name",
          "type":"string"
        }
      ],
      "name":"NameChanged",
      "type":"event"
    },
    {
      "anonymous":false,
      "inputs":[
        {
          "indexed":true,
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        },
        {
          "indexed":false,
          "internalType":"bytes32",
          "name":"x",
          "type":"bytes32"
        },
        {
          "indexed":false,
          "internalType":"bytes32",
          "name":"y",
          "type":"bytes32"
        }
      ],
      "name":"PubkeyChanged",
      "type":"event"
    },
    {
      "anonymous":false,
      "inputs":[
        {
          "indexed":true,
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        },
        {
          "indexed":true,
          "internalType":"string",
          "name":"indexedKey",
          "type":"string"
        },
        {
          "indexed":false,
          "internalType":"string",
          "name":"key",
          "type":"string"
        }
      ],
      "name":"TextChanged",
      "type":"event"
    },
    {
      "constant":true,
      "inputs":[
        {
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        },
        {
          "internalType":"uint256",
          "name":"contentTypes",
          "type":"uint256"
        }
      ],
      "name":"ABI",
      "outputs":[
        {
          "internalType":"uint256",
          "name":"",
          "type":"uint256"
        },
        {
          "internalType":"bytes",
          "name":"",
          "type":"bytes"
        }
      ],
      "payable":false,
      "stateMutability":"view",
      "type":"function"
    },
    {
      "constant":true,
      "inputs":[
        {
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        }
      ],
      "name":"addr",
      "outputs":[
        {
          "internalType":"address payable",
          "name":"",
          "type":"address"
        }
      ],
      "payable":false,
      "stateMutability":"view",
      "type":"function"
    },
    {
      "constant":true,
      "inputs":[
        {
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        },
        {
          "internalType":"uint256",
          "name":"coinType",
          "type":"uint256"
        }
      ],
      "name":"addr",
      "outputs":[
        {
          "internalType":"bytes",
          "name":"",
          "type":"bytes"
        }
      ],
      "payable":false,
      "stateMutability":"view",
      "type":"function"
    },
    {
      "constant":true,
      "inputs":[
        {
          "internalType":"bytes32",
          "name":"",
          "type":"bytes32"
        },
        {
          "internalType":"address",
          "name":"",
          "type":"address"
        },
        {
          "internalType":"address",
          "name":"",
          "type":"address"
        }
      ],
      "name":"authorisations",
      "outputs":[
        {
          "internalType":"bool",
          "name":"",
          "type":"bool"
        }
      ],
      "payable":false,
      "stateMutability":"view",
      "type":"function"
    },
    {
      "constant":false,
      "inputs":[
        {
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        }
      ],
      "name":"clearDNSZone",
      "outputs":[

      ],
      "payable":false,
      "stateMutability":"nonpayable",
      "type":"function"
    },
    {
      "constant":true,
      "inputs":[
        {
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        }
      ],
      "name":"contenthash",
      "outputs":[
        {
          "internalType":"bytes",
          "name":"",
          "type":"bytes"
        }
      ],
      "payable":false,
      "stateMutability":"view",
      "type":"function"
    },
    {
      "constant":true,
      "inputs":[
        {
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        },
        {
          "internalType":"bytes32",
          "name":"name",
          "type":"bytes32"
        },
        {
          "internalType":"uint16",
          "name":"resource",
          "type":"uint16"
        }
      ],
      "name":"dnsRecord",
      "outputs":[
        {
          "internalType":"bytes",
          "name":"",
          "type":"bytes"
        }
      ],
      "payable":false,
      "stateMutability":"view",
      "type":"function"
    },
    {
      "constant":true,
      "inputs":[
        {
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        },
        {
          "internalType":"bytes32",
          "name":"name",
          "type":"bytes32"
        }
      ],
      "name":"hasDNSRecords",
      "outputs":[
        {
          "internalType":"bool",
          "name":"",
          "type":"bool"
        }
      ],
      "payable":false,
      "stateMutability":"view",
      "type":"function"
    },
    {
      "constant":true,
      "inputs":[
        {
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        },
        {
          "internalType":"bytes4",
          "name":"interfaceID",
          "type":"bytes4"
        }
      ],
      "name":"interfaceImplementer",
      "outputs":[
        {
          "internalType":"address",
          "name":"",
          "type":"address"
        }
      ],
      "payable":false,
      "stateMutability":"view",
      "type":"function"
    },
    {
      "constant":false,
      "inputs":[
        {
          "internalType":"bytes[]",
          "name":"data",
          "type":"bytes[]"
        }
      ],
      "name":"multicall",
      "outputs":[
        {
          "internalType":"bytes[]",
          "name":"results",
          "type":"bytes[]"
        }
      ],
      "payable":false,
      "stateMutability":"nonpayable",
      "type":"function"
    },
    {
      "constant":true,
      "inputs":[
        {
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        }
      ],
      "name":"name",
      "outputs":[
        {
          "internalType":"string",
          "name":"",
          "type":"string"
        }
      ],
      "payable":false,
      "stateMutability":"view",
      "type":"function"
    },
    {
      "constant":true,
      "inputs":[
        {
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        }
      ],
      "name":"pubkey",
      "outputs":[
        {
          "internalType":"bytes32",
          "name":"x",
          "type":"bytes32"
        },
        {
          "internalType":"bytes32",
          "name":"y",
          "type":"bytes32"
        }
      ],
      "payable":false,
      "stateMutability":"view",
      "type":"function"
    },
    {
      "constant":false,
      "inputs":[
        {
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        },
        {
          "internalType":"uint256",
          "name":"contentType",
          "type":"uint256"
        },
        {
          "internalType":"bytes",
          "name":"data",
          "type":"bytes"
        }
      ],
      "name":"setABI",
      "outputs":[

      ],
      "payable":false,
      "stateMutability":"nonpayable",
      "type":"function"
    },
    {
      "constant":false,
      "inputs":[
        {
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        },
        {
          "internalType":"uint256",
          "name":"coinType",
          "type":"uint256"
        },
        {
          "internalType":"bytes",
          "name":"a",
          "type":"bytes"
        }
      ],
      "name":"setAddr",
      "outputs":[

      ],
      "payable":false,
      "stateMutability":"nonpayable",
      "type":"function"
    },
    {
      "constant":false,
      "inputs":[
        {
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        },
        {
          "internalType":"address",
          "name":"a",
          "type":"address"
        }
      ],
      "name":"setAddr",
      "outputs":[

      ],
      "payable":false,
      "stateMutability":"nonpayable",
      "type":"function"
    },
    {
      "constant":false,
      "inputs":[
        {
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        },
        {
          "internalType":"address",
          "name":"target",
          "type":"address"
        },
        {
          "internalType":"bool",
          "name":"isAuthorised",
          "type":"bool"
        }
      ],
      "name":"setAuthorisation",
      "outputs":[

      ],
      "payable":false,
      "stateMutability":"nonpayable",
      "type":"function"
    },
    {
      "constant":false,
      "inputs":[
        {
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        },
        {
          "internalType":"bytes",
          "name":"hash",
          "type":"bytes"
        }
      ],
      "name":"setContenthash",
      "outputs":[

      ],
      "payable":false,
      "stateMutability":"nonpayable",
      "type":"function"
    },
    {
      "constant":false,
      "inputs":[
        {
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        },
        {
          "internalType":"bytes",
          "name":"data",
          "type":"bytes"
        }
      ],
      "name":"setDNSRecords",
      "outputs":[

      ],
      "payable":false,
      "stateMutability":"nonpayable",
      "type":"function"
    },
    {
      "constant":false,
      "inputs":[
        {
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        },
        {
          "internalType":"bytes4",
          "name":"interfaceID",
          "type":"bytes4"
        },
        {
          "internalType":"address",
          "name":"implementer",
          "type":"address"
        }
      ],
      "name":"setInterface",
      "outputs":[

      ],
      "payable":false,
      "stateMutability":"nonpayable",
      "type":"function"
    },
    {
      "constant":false,
      "inputs":[
        {
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        },
        {
          "internalType":"string",
          "name":"name",
          "type":"string"
        }
      ],
      "name":"setName",
      "outputs":[

      ],
      "payable":false,
      "stateMutability":"nonpayable",
      "type":"function"
    },
    {
      "constant":false,
      "inputs":[
        {
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        },
        {
          "internalType":"bytes32",
          "name":"x",
          "type":"bytes32"
        },
        {
          "internalType":"bytes32",
          "name":"y",
          "type":"bytes32"
        }
      ],
      "name":"setPubkey",
      "outputs":[

      ],
      "payable":false,
      "stateMutability":"nonpayable",
      "type":"function"
    },
    {
      "constant":false,
      "inputs":[
        {
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        },
        {
          "internalType":"string",
          "name":"key",
          "type":"string"
        },
        {
          "internalType":"string",
          "name":"value",
          "type":"string"
        }
      ],
      "name":"setText",
      "outputs":[

      ],
      "payable":false,
      "stateMutability":"nonpayable",
      "type":"function"
    },
    {
      "constant":true,
      "inputs":[
        {
          "internalType":"bytes4",
          "name":"interfaceID",
          "type":"bytes4"
        }
      ],
      "name":"supportsInterface",
      "outputs":[
        {
          "internalType":"bool",
          "name":"",
          "type":"bool"
        }
      ],
      "payable":false,
      "stateMutability":"pure",
      "type":"function"
    },
    {
      "constant":true,
      "inputs":[
        {
          "internalType":"bytes32",
          "name":"node",
          "type":"bytes32"
        },
        {
          "internalType":"string",
          "name":"key",
          "type":"string"
        }
      ],
      "name":"text",
      "outputs":[
        {
          "internalType":"string",
          "name":"",
          "type":"string"
        }
      ],
      "payable":false,
      "stateMutability":"view",
      "type":"function"
    }
  ]


================================================
FILE: bin/console
================================================
#!/usr/bin/env ruby

# use the local version of the code instead of a globally installed gem
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)

require "eth"
include Eth

require "pry"
Pry.start


================================================
FILE: bin/setup
================================================
#!/usr/bin/env bash

bundle install
git submodule update --init --recursive
rufo .
yard doc
rspec

echo "Tests fail? Run \`geth --dev --http --ipcpath /tmp/geth.ipc\` in background and try again."


================================================
FILE: codecov.yml
================================================
coverage:
  status:
    project:
      default:
        target: 99%
        threshold: 1%


================================================
FILE: eth.gemspec
================================================
# frozen_string_literal: true
# coding: utf-8

lib = File.expand_path("lib", __dir__).freeze
$LOAD_PATH.unshift lib unless $LOAD_PATH.include? lib

require "eth/version"

Gem::Specification.new do |spec|
  spec.name = "eth"
  spec.version = Eth::VERSION
  spec.authors = ["Steve Ellis", "Afri Schoedon"]
  spec.email = ["email@steveell.is", "ruby@q9f.cc"]

  spec.summary = %q{Ruby Ethereum library.}
  spec.description = %q{Library to handle Ethereum accounts, messages, and transactions.}
  spec.homepage = "https://github.com/q9f/eth.rb"
  spec.license = "Apache-2.0"

  spec.metadata = {
    "bug_tracker_uri" => "https://github.com/q9f/eth.rb/issues",
    "changelog_uri" => "https://github.com/q9f/eth.rb/blob/main/CHANGELOG.md",
    "documentation_uri" => "https://q9f.github.io/eth.rb/",
    "github_repo" => "https://github.com/q9f/eth.rb",
    "source_code_uri" => "https://github.com/q9f/eth.rb",
  }.freeze

  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
  spec.bindir = "exe"
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
  spec.require_paths = ["lib", "abis"]
  spec.test_files = spec.files.grep %r{^(test|spec|features)/}

  spec.platform = Gem::Platform::RUBY
  spec.required_ruby_version = ">= 3.0", "< 5.0"

  # bigdecimal for big decimals ;)
  spec.add_dependency "bigdecimal", "~> 3.1"

  # forwardable for contracts meta programming
  spec.add_dependency "forwardable", "~> 1.3"

  # keccak for hashing everything in ethereum
  spec.add_dependency "keccak", "~> 1.3"

  # konstructor gem for overloading constructors
  spec.add_dependency "konstructor", "~> 1.0"

  # rbsecp256k1 for key-pairs and signatures
  spec.add_dependency "rbsecp256k1", "~> 6.0"

  # openssl for encrypted key derivation
  spec.add_dependency "openssl", "~> 3.3"

  # base64 is required explicitly in Ruby >= 3.4
  spec.add_dependency "base64", "~> 0.1"

  # scrypt for encrypted key derivation
  spec.add_dependency "scrypt", "~> 3.0"

  # bls12-381 for BLS signatures and pairings
  spec.add_dependency "bls12-381", "~> 0.3"

  # httpx for HTTP/2 and persistent connections
  spec.add_dependency "httpx", "~> 1.6"
end


================================================
FILE: lib/eth/abi/decoder.rb
================================================
# Copyright (c) 2016-2025 The Ruby-Eth Contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# -*- encoding : ascii-8bit -*-

# Provides the {Eth} module.
module Eth

  # Provides a Ruby implementation of the Ethereum Application Binary Interface (ABI).
  module Abi

    # Provides a utility module to assist decoding ABIs.
    module Decoder
      extend self

      # Decodes a specific value, either static or dynamic.
      #
      # @param type [Eth::Abi::Type] type to be decoded.
      # @param arg [String] encoded type data string.
      # @return [String] the decoded data for the type.
      # @raise [DecodingError] if decoding fails for type.
      def type(type, arg)
        if %w(string bytes).include?(type.base_type) and type.sub_type.empty? and type.dimensions.empty?
          l = Util.deserialize_big_endian_to_int arg[0, 32]
          data = arg[32..-1]
          raise DecodingError, "Wrong data size for string/bytes object" unless data.size == Util.ceil32(l)

          # decoded strings and bytes
          data[0, l]
        elsif type.base_type == "tuple" && type.dimensions.empty?
          offset = 0
          result = []
          raise DecodingError, "Cannot decode tuples without known components" if type.components.nil?

          head_offset = 0
          dynamic_offsets = []
          type.components.each_with_index do |component, index|
            if component.dynamic?
              raise DecodingError, "Offset out of bounds" if head_offset + 32 > arg.size
              pointer = Util.deserialize_big_endian_to_int arg[head_offset, 32]
              dynamic_offsets << [index, pointer]
              head_offset += 32
            else
              size = component.size
              raise DecodingError, "Offset out of bounds" if head_offset + size > arg.size
              head_offset += size
            end
          end

          dynamic_ranges = tuple_dynamic_ranges(dynamic_offsets, arg.size, head_offset)

          type.components.each_with_index do |component, index|
            if component.dynamic?
              pointer, next_offset = dynamic_ranges[index]
              raise DecodingError, "Offset out of bounds" if pointer > arg.size || next_offset > arg.size
              raise DecodingError, "Offset out of bounds" if next_offset < pointer
              result << type(component, arg[pointer, next_offset - pointer])
              offset += 32
            else
              size = component.size
              raise DecodingError, "Offset out of bounds" if offset + size > arg.size
              result << type(component, arg[offset, size])
              offset += size
            end
          end
          result
        elsif type.dynamic? && !type.dimensions.empty? && type.dimensions.last == 0
          l = Util.deserialize_big_endian_to_int arg[0, 32]
          nested_sub = type.nested_sub

          if nested_sub.dynamic?
            raise DecodingError, "Wrong data size for dynamic array" unless arg.size >= 32 + 32 * l
            offsets = (0...l).map do |i|
              off = Util.deserialize_big_endian_to_int arg[32 + 32 * i, 32]
              raise DecodingError, "Offset out of bounds" if off < 32 * l || off > arg.size - 64
              off
            end
            offsets.each_with_index.map do |off, index|
              start = 32 + off
              stop = index + 1 < offsets.length ? 32 + offsets[index + 1] : arg.size
              raise DecodingError, "Offset out of bounds" if stop > arg.size || stop < start
              type(nested_sub, arg[start, stop - start])
            end
          else
            raise DecodingError, "Wrong data size for dynamic array" unless arg.size >= 32 + nested_sub.size * l
            # decoded dynamic-sized arrays with static sub-types
            (0...l).map { |i| type(nested_sub, arg[32 + nested_sub.size * i, nested_sub.size]) }
          end
        elsif !type.dimensions.empty?
          l = type.dimensions.last
          nested_sub = type.nested_sub

          if nested_sub.dynamic?
            raise DecodingError, "Wrong data size for static array" unless arg.size >= 32 * l
            offsets = (0...l).map do |i|
              off = Util.deserialize_big_endian_to_int arg[32 * i, 32]
              raise DecodingError, "Offset out of bounds" if off < 32 * l || off > arg.size - 32
              off
            end
            offsets.each_with_index.map do |off, i|
              size = (i + 1 < offsets.length ? offsets[i + 1] : arg.size) - off
              type(nested_sub, arg[off, size])
            end
          else
            # decoded static-size arrays with static sub-types
            (0...l).map { |i| type(nested_sub, arg[nested_sub.size * i, nested_sub.size]) }
          end
        else

          # decoded primitive types
          primitive_type type, arg
        end
      end

      # Decodes primitive types.
      #
      # @param type [Eth::Abi::Type] type to be decoded.
      # @param data [String] encoded primitive type data string.
      # @return [String] the decoded data for the type.
      # @raise [DecodingError] if decoding fails for type.
      def primitive_type(type, data)
        case type.base_type
        when "address"

          # decoded address with 0x-prefix
          Address.new(Util.bin_to_hex data[12..-1]).to_s.downcase
        when "string", "bytes"
          if type.sub_type.empty?
            size = Util.deserialize_big_endian_to_int data[0, 32]

            # decoded dynamic-sized array
            decoded = data[32..-1][0, size]
            decoded.force_encoding(Encoding::UTF_8)
            decoded
          else

            # decoded static-sized array
            data[0, type.sub_type.to_i]
          end
        when "hash"

          # decoded hash
          data[(32 - type.sub_type.to_i), type.sub_type.to_i]
        when "uint"

          # decoded unsigned integer
          Util.deserialize_big_endian_to_int data
        when "int"
          u = Util.deserialize_big_endian_to_int data
          i = u >= 2 ** (type.sub_type.to_i - 1) ? (u - 2 ** 256) : u

          # decoded integer
          i
        when "ureal", "ufixed"
          high, low = type.sub_type.split("x").map(&:to_i)

          # decoded unsigned fixed point numeric
          Util.deserialize_big_endian_to_int(data) * 1.0 / 2 ** low
        when "real", "fixed"
          high, low = type.sub_type.split("x").map(&:to_i)
          u = Util.deserialize_big_endian_to_int data
          i = u >= 2 ** (high + low - 1) ? (u - 2 ** (high + low)) : u

          # decoded fixed point numeric
          i * 1.0 / 2 ** low
        when "bool"

          # decoded boolean
          data[-1] == Constant::BYTE_ONE
        else
          raise DecodingError, "Unknown primitive type: #{type.base_type}"
        end
      end

      private

      # Computes the byte ranges for dynamic tuple components.
      #
      # @param offsets [Array<Array(Integer, Integer)>] list of tuples containing the component index and pointer.
      # @param total_size [Integer] total number of bytes available for the tuple.
      # @param head_size [Integer] size in bytes of the tuple head.
      # @return [Hash{Integer=>Array(Integer, Integer)}] mapping component index to a [start, stop) range.
      # @raise [DecodingError] if the encoded offsets overlap or leave the tuple head.
      def tuple_dynamic_ranges(offsets, total_size, head_size)
        ranges = {}
        sorted = offsets.sort_by { |(_, pointer)| pointer }
        sorted.each_with_index do |(index, pointer), idx|
          raise DecodingError, "Offset out of bounds" if pointer < head_size || pointer > total_size
          next_pointer = idx + 1 < sorted.length ? sorted[idx + 1][1] : total_size
          raise DecodingError, "Offset out of bounds" if next_pointer < pointer || next_pointer > total_size
          ranges[index] = [pointer, next_pointer]
        end
        ranges
      end
    end
  end
end


================================================
FILE: lib/eth/abi/encoder.rb
================================================
# Copyright (c) 2016-2025 The Ruby-Eth Contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# -*- encoding : ascii-8bit -*-
require "bigdecimal"

# Provides the {Eth} module.
module Eth

  # Provides a Ruby implementation of the Ethereum Application Binary Interface (ABI).
  module Abi

    # Provides a utility module to assist encoding ABIs.
    module Encoder
      extend self

      # Encodes a specific value, either static or dynamic.
      #
      # @param type [Eth::Abi::Type] type to be encoded.
      # @param arg [String|Number] value to be encoded.
      # @return [String] the encoded type.
      # @raise [EncodingError] if value does not match type.
      def type(type, arg)
        if %w(string bytes).include? type.base_type and type.sub_type.empty? and type.dimensions.empty?
          raise EncodingError, "Argument must be a String" unless arg.instance_of? String
          arg = handle_hex_string arg, type

          # encodes strings and bytes
          size = type Type.size_type, arg.size
          padding = Constant::BYTE_ZERO * (Util.ceil32(arg.size) - arg.size)
          "#{size}#{arg}#{padding}"
        elsif type.base_type == "tuple" && type.dimensions.empty?
          tuple arg, type
        elsif !type.dimensions.empty?
          encode_array type, arg
        else
          primitive_type type, arg
        end
      end

      # Encodes primitive types.
      #
      # @param type [Eth::Abi::Type] type to be encoded.
      # @param arg [String|Number] value to be encoded.
      # @return [String] the encoded primitive type.
      # @raise [EncodingError] if value does not match type.
      # @raise [ValueOutOfBounds] if value is out of bounds for type.
      # @raise [ArgumentError] if encoding fails for type.
      def primitive_type(type, arg)
        case type.base_type
        when "uint"
          uint arg, type
        when "int"
          int arg, type
        when "bool"
          bool arg
        when "ureal", "ufixed"
          ufixed arg, type
        when "real", "fixed"
          fixed arg, type
        when "string", "bytes"
          bytes arg, type
        when "tuple"
          tuple arg, type
        when "hash"
          hash arg, type
        when "address"
          address arg
        else
          raise EncodingError, "Unhandled type: #{type.base_type} #{type.sub_type}"
        end
      end

      private

      # Properly encodes unsigned integers.
      def uint(arg, type)
        arg = coerce_number arg
        raise ArgumentError, "Don't know how to handle this input." unless arg.is_a? Numeric
        raise ValueOutOfBounds, "Number out of range: #{arg}" if arg > Constant::UINT_MAX or arg < Constant::UINT_MIN
        real_size = type.sub_type.to_i
        i = arg.to_i
        raise ValueOutOfBounds, arg unless i >= 0 and i < 2 ** real_size
        Util.zpad_int i
      end

      # Properly encodes signed integers.
      def int(arg, type)
        arg = coerce_number arg
        raise ArgumentError, "Don't know how to handle this input." unless arg.is_a? Numeric
        raise ValueOutOfBounds, "Number out of range: #{arg}" if arg > Constant::INT_MAX or arg < Constant::INT_MIN
        real_size = type.sub_type.to_i
        i = arg.to_i
        raise ValueOutOfBounds, arg unless i >= -2 ** (real_size - 1) and i < 2 ** (real_size - 1)
        Util.zpad_int(i % 2 ** 256)
      end

      # Properly encodes booleans.
      def bool(arg)
        raise EncodingError, "Argument is not bool: #{arg}" unless arg.instance_of? TrueClass or arg.instance_of? FalseClass
        Util.zpad_int(arg ? 1 : 0)
      end

      # Properly encodes unsigned fixed-point numbers.
      def ufixed(arg, type)
        arg = coerce_number arg
        raise ArgumentError, "Don't know how to handle this input." unless arg.is_a? Numeric
        high, low = type.sub_type.split("x").map(&:to_i)
        raise ValueOutOfBounds, arg unless arg >= 0 and arg < 2 ** high
        Util.zpad_int((arg * 2 ** low).to_i)
      end

      # Properly encodes signed fixed-point numbers.
      def fixed(arg, type)
        arg = coerce_number arg
        raise ArgumentError, "Don't know how to handle this input." unless arg.is_a? Numeric
        high, low = type.sub_type.split("x").map(&:to_i)
        raise ValueOutOfBounds, arg unless arg >= -2 ** (high - 1) and arg < 2 ** (high - 1)
        i = (arg * 2 ** low).to_i
        Util.zpad_int(i % 2 ** (high + low))
      end

      # Properly encodes byte-strings.
      def bytes(arg, type)
        raise EncodingError, "Expecting String: #{arg}" unless arg.instance_of? String
        arg = handle_hex_string arg, type

        if type.sub_type.empty?
          size = Util.zpad_int arg.size
          padding = Constant::BYTE_ZERO * (Util.ceil32(arg.size) - arg.size)

          # variable length string/bytes
          "#{size}#{arg}#{padding}"
        else
          raise ValueOutOfBounds, arg unless arg.size <= type.sub_type.to_i
          padding = Constant::BYTE_ZERO * (32 - arg.size)

          # fixed length string/bytes
          "#{arg}#{padding}"
        end
      end

      # Properly encodes tuples.
      def tuple(arg, type)
        unless arg.is_a?(Hash) || arg.is_a?(Array)
          raise EncodingError, "Expecting Hash or Array: #{arg}"
        end
        raise EncodingError, "Expecting #{type.components.size} elements: #{arg}" unless arg.size == type.components.size
        arg = arg.transform_keys(&:to_s) if arg.is_a?(Hash) # because component_type.name is String

        static_size = 0
        type.components.each_with_index do |component, i|
          if type.components[i].dynamic?
            static_size += 32
          else
            static_size += Util.ceil32(type.components[i].size || 0)
          end
        end

        dynamic_offset = static_size
        offsets_and_static_values = []
        dynamic_values = []

        type.components.each_with_index do |component, i|
          component_type = type.components[i]
          if component_type.dynamic?
            offsets_and_static_values << type(Type.size_type, dynamic_offset)
            dynamic_value = type(component_type, arg.is_a?(Array) ? arg[i] : arg[component_type.name])
            dynamic_values << dynamic_value
            dynamic_offset += dynamic_value.size
          else
            offsets_and_static_values << type(component_type, arg.is_a?(Array) ? arg[i] : arg.fetch(component_type.name))
          end
        end

        offsets_and_static_values.join + dynamic_values.join
      end

      def coerce_number(arg)
        return arg if arg.is_a? Numeric
        return arg.to_i(0) if arg.is_a?(String) && arg.match?(/^-?(0x)?[0-9a-fA-F]+$/)
        return BigDecimal(arg) if arg.is_a?(String) && arg.match?(/^-?\d+(\.\d+)?$/)
        arg
      end

      # Encodes array values of any dimensionality.
      #
      # @param type [Eth::Abi::Type] the type describing the array.
      # @param values [Array] the Ruby values to encode.
      # @return [String] ABI encoded array payload.
      # @raise [EncodingError] if the value cardinality does not match static dimensions.
      def encode_array(type, values)
        raise EncodingError, "Expecting Array value" unless values.is_a?(Array)

        required_length = type.dimensions.last
        if required_length != 0 && values.size != required_length
          raise EncodingError, "Expecting #{required_length} elements: #{values.size} provided"
        end

        nested_sub = type.nested_sub

        if required_length.zero?
          encode_dynamic_array(nested_sub, values)
        else
          encode_static_array(nested_sub, values)
        end
      end

      # Encodes dynamic-sized arrays, including nested tuples.
      #
      # @param nested_sub [Eth::Abi::Type] the element type.
      # @param values [Array] elements to encode.
      # @return [String] ABI encoded dynamic array payload.
      def encode_dynamic_array(nested_sub, values)
        head = type(Type.size_type, values.size)
        element_heads, element_tails = encode_array_elements(nested_sub, values)
        head + element_heads + element_tails
      end

      # Encodes static-sized arrays, including nested tuples.
      #
      # @param nested_sub [Eth::Abi::Type] the element type.
      # @param values [Array] elements to encode.
      # @return [String] ABI encoded static array payload.
      def encode_static_array(nested_sub, values)
        element_heads, element_tails = encode_array_elements(nested_sub, values)
        element_heads + element_tails
      end

      # Encodes the head/tail portions for array elements.
      #
      # @param nested_sub [Eth::Abi::Type] the element type.
      # @param values [Array] elements to encode.
      # @return [Array<String, String>] head/tail encoded segments.
      def encode_array_elements(nested_sub, values)
        if nested_sub.dynamic?
          head = ""
          tail = ""
          offset = values.size * 32
          values.each do |value|
            encoded = type(nested_sub, value)
            head += type(Type.size_type, offset)
            tail += encoded
            offset += encoded.size
          end
          [head, tail]
        else
          [values.map { |value| type(nested_sub, value) }.join, ""]
        end
      end

      # Properly encodes hash-strings.
      def hash(arg, type)
        size = type.sub_type.to_i
        raise EncodingError, "Argument too long: #{arg}" unless size > 0 and size <= 32
        if arg.is_a? Integer

          # hash from integer
          Util.zpad_int arg
        elsif arg.size == size

          # hash from encoded hash
          Util.zpad arg, 32
        elsif arg.size == size * 2

          # hash from hexadecimal hash
          Util.zpad_hex arg
        else
          raise EncodingError, "Could not parse hash: #{arg}"
        end
      end

      # Properly encodes addresses.
      def address(arg)
        if arg.is_a? Address

          # from checksummed address with 0x prefix
          Util.zpad_hex arg.to_s[2..-1]
        elsif arg.is_a? Integer

          # address from integer
          Util.zpad_int arg
        elsif arg.size == 20

          # address from encoded address
          Util.zpad arg, 32
        elsif arg.size == 40

          # address from hexadecimal address
          Util.zpad_hex arg
        elsif arg.size == 42 and arg[0, 2] == "0x"

          # address from hexadecimal address with 0x prefix
          Util.zpad_hex arg[2..-1]
        else
          raise EncodingError, "Could not parse address: #{arg}"
        end
      end

      # The ABI encoder needs to be able to determine between a hex `"123"`
      # and a binary `"123"` string.
      def handle_hex_string(arg, type)
        if Util.prefixed? arg or
           (arg.size === type.sub_type.to_i * 2 and Util.hex? arg)

          # There is no way telling whether a string is hex or binary with certainty
          # in Ruby. Therefore, we assume a `0x` prefix to indicate a hex string.
          # Additionally, if the string size is exactly the double of the expected
          # binary size, we can assume a hex value.
          Util.hex_to_bin arg
        else

          # Everything else will be assumed binary or raw string.
          arg.b
        end
      end
    end
  end
end


================================================
FILE: lib/eth/abi/event.rb
================================================
# Copyright (c) 2016-2025 The Ruby-Eth Contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# -*- encoding : ascii-8bit -*-

# Provides the {Eth} module.
module Eth

  # Provides a Ruby implementation of the Ethereum Application Binary Interface (ABI).
  module Abi

    # Provides a module to decode transaction log events.
    module Event
      extend self

      # Compute topic for ABI event interface.
      #
      # @param interface [Hash] ABI event interface.
      # @return [String] a hex-string topic.
      def compute_topic(interface)
        sig = signature(interface)
        Util.prefix_hex(Util.bin_to_hex(Util.keccak256(sig)))
      end

      # Build event signature string from ABI interface.
      #
      # @param interface [Hash] ABI event interface.
      # @return [String] interface signature string.
      def signature(interface)
        name = interface.fetch("name")
        inputs = interface.fetch("inputs", [])
        types = inputs.map { |i| type(i) }
        "#{name}(#{types.join(",")})"
      end

      # Gets the input type for events.
      #
      # @param input [Hash] events input.
      # @return [String] input type.
      def type(input)
        if input["type"] == "tuple"
          "(#{input["components"].map { |c| type(c) }.join(",")})"
        elsif input["type"] == "enum"
          "uint8"
        else
          input["type"]
        end
      end

      # A decoded event log.
      class LogDescription
        # The event ABI interface used to decode the log.
        attr_accessor :event_interface

        # The the input argument of the event.
        attr_accessor :args

        # The named input argument of the event.
        attr_accessor :kwargs

        # The topic hash.
        attr_accessor :topic

        # Decodes event log argument values.
        #
        # @param event_interface [Hash] event ABI type.
        # @param log [Hash] transaction receipt log
        def initialize(event_interface, log)
          @event_interface = event_interface

          inputs = event_interface.fetch("inputs")
          data = log.fetch("data")
          topics = log.fetch("topics", [])
          anonymous = event_interface.fetch("anonymous", false)

          @topic = topics[0] if !anonymous
          @args, @kwargs = Event.decode_log(inputs, data, topics, anonymous)
        end

        # The event name. (e.g. Transfer)
        def name
          @name ||= event_interface.fetch("name")
        end

        # The event signature. (e.g. Transfer(address,address,uint256))
        def signature
          @signature ||= Abi::Event.signature(event_interface)
        end
      end

      # Decodes a stream of receipt logs with a set of ABI interfaces.
      #
      # @param interfaces [Array] event ABI types.
      # @param logs [Array] transaction receipt logs
      # @return [Hash] an enumerator of LogDescription objects.
      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

      # Decodes event log argument values.
      #
      # @param inputs [Array] event ABI types.
      # @param data [String] ABI event data to be decoded.
      # @param topics [Array] ABI event topics to be decoded.
      # @param anonymous [Boolean] If event signature is excluded from topics.
      # @return [[Array, Hash]] decoded positional arguments and decoded keyword arguments.
      # @raise [DecodingError] if decoding fails for type.
      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
    end
  end
end


================================================
FILE: lib/eth/abi/function.rb
================================================
# Copyright (c) 2016-2025 The Ruby-Eth Contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# -*- encoding : ascii-8bit -*-

# Provides the {Eth} module.
module Eth

  # Provides a Ruby implementation of the Ethereum Application Binary Interface (ABI).
  module Abi

    # Provides a module to decode transaction input data.
    module Function
      extend self

      # Build function signature string from ABI interface.
      #
      # @param interface [Hash] ABI function interface.
      # @return [String] interface signature string.
      def signature(interface)
        name = interface.fetch("name")
        inputs = interface.fetch("inputs", [])
        types = inputs.map { |i| type(i) }
        "#{name}(#{types.join(",")})"
      end

      # Compute selector for ABI function interface.
      #
      # @param interface [Hash] ABI function interface.
      # @return [String] a hex-string selector.
      def selector(interface)
        sig = signature(interface)
        Util.prefix_hex(Util.bin_to_hex(Util.keccak256(sig))[0, 8])
      end

      # Gets the input type for functions.
      #
      # @param input [Hash] function input.
      # @return [String] input type.
      def type(input)
        if input["type"] == "tuple"
          "(#{input["components"].map { |c| type(c) }.join(",")})"
        elsif input["type"] == "enum"
          "uint8"
        else
          input["type"]
        end
      end

      # A decoded function call.
      class CallDescription
        # The function ABI interface used to decode the call.
        attr_accessor :function_interface

        # The positional arguments of the call.
        attr_accessor :args

        # The named arguments of the call.
        attr_accessor :kwargs

        # The function selector.
        attr_accessor :selector

        # Creates a description object for a decoded function call.
        #
        # @param function_interface [Hash] function ABI type.
        # @param selector [String] function selector hex-string.
        # @param args [Array] decoded positional arguments.
        # @param kwargs [Hash] decoded keyword arguments.
        def initialize(function_interface, selector, args, kwargs)
          @function_interface = function_interface
          @selector = selector
          @args = args
          @kwargs = kwargs
        end

        # The function name. (e.g. transfer)
        def name
          @name ||= function_interface.fetch("name")
        end

        # The function signature. (e.g. transfer(address,uint256))
        def signature
          @signature ||= Function.signature(function_interface)
        end
      end

      # Decodes a transaction input with a set of ABI interfaces.
      #
      # @param interfaces [Array] function ABI types.
      # @param data [String] transaction input data.
      # @return [CallDescription, nil] a CallDescription object or nil if selector unknown.
      def decode(interfaces, data)
        data = Util.remove_hex_prefix(data)
        selector = Util.prefix_hex(data[0, 8])
        payload = Util.prefix_hex(data[8..] || "")

        selector_to_interfaces = Hash[interfaces.map { |i| [selector(i), i] }]
        if (interface = selector_to_interfaces[selector])
          inputs = interface.fetch("inputs", [])
          types = inputs.map { |i| type(i) }
          args = Abi.decode(types, payload)
          kwargs = {}
          inputs.each_with_index do |input, i|
            name = input.fetch("name", "")
            kwargs[name.to_sym] = args[i] unless name.empty?
          end
          CallDescription.new(interface, selector, args, kwargs)
        end
      end
    end
  end
end


================================================
FILE: lib/eth/abi/packed/encoder.rb
================================================
# Copyright (c) 2016-2025 The Ruby-Eth Contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# -*- encoding : ascii-8bit -*-

# Provides the {Eth} module.
module Eth

  # Provides a Ruby implementation of the Ethereum Application Binary Interface (ABI).
  module Abi

    # Encapsulates the module for non-standard packed encoding used in Solidity.
    module Packed

      # Provides a utility module to assist encoding ABIs.
      module Encoder
        extend self

        # Encodes a specific value, either static or dynamic in non-standard
        # packed encoding mode.
        #
        # @param type [Eth::Abi::Type] type to be encoded.
        # @param arg [String|Number] value to be encoded.
        # @return [String] the packed encoded type.
        # @raise [EncodingError] if value does not match type.
        # @raise [ArgumentError] if encoding fails for type.
        def type(type, arg)
          case type
          when /^uint(\d+)$/
            uint(arg, $1.to_i / 8)
          when /^int(\d+)$/
            int(arg, $1.to_i / 8)
          when "bool"
            bool(arg)
          when /^ureal(\d+)x(\d+)$/, /^ufixed(\d+)x(\d+)$/
            ufixed(arg, $1.to_i / 8, $2.to_i)
          when /^real(\d+)x(\d+)$/, /^fixed(\d+)x(\d+)$/
            fixed(arg, $1.to_i / 8, $2.to_i)
          when "string"
            string(arg)
          when /^bytes(\d+)$/
            bytes(arg, $1.to_i)
          when "bytes"
            string(arg)
          when /^tuple\((.+)\)$/
            tuple($1.split(","), arg)
          when /^hash(\d+)$/
            hash(arg, $1.to_i / 8)
          when "address"
            address(arg)
          when /^(.+)\[\]$/
            array($1, arg)
          when /^(.+)\[(\d+)\]$/
            fixed_array($1, arg, $2.to_i)
          else
            raise EncodingError, "Unhandled type: #{type}"
          end
        end

        private

        # Properly encodes signed integers.
        def uint(value, byte_size)
          raise ArgumentError, "Don't know how to handle this input." unless value.is_a? Numeric
          raise ValueOutOfBounds, "Number out of range: #{value}" if value > Constant::UINT_MAX or value < Constant::UINT_MIN
          i = value.to_i
          Util.zpad_int i, byte_size
        end

        # Properly encodes signed integers.
        def int(value, byte_size)
          raise ArgumentError, "Don't know how to handle this input." unless value.is_a? Numeric
          raise ValueOutOfBounds, "Number out of range: #{value}" if value > Constant::INT_MAX or value < Constant::INT_MIN
          real_size = byte_size * 8
          i = value.to_i % 2 ** real_size
          Util.zpad_int i, byte_size
        end

        # Properly encodes booleans.
        def bool(value)
          raise EncodingError, "Argument is not bool: #{value}" unless value.instance_of? TrueClass or value.instance_of? FalseClass
          (value ? "\x01" : "\x00").b
        end

        # Properly encodes unsigned fixed-point numbers.
        def ufixed(value, byte_size, decimals)
          raise ArgumentError, "Don't know how to handle this input." unless value.is_a? Numeric
          raise ValueOutOfBounds, value unless value >= 0 and value < 2 ** decimals
          scaled_value = (value * (10 ** decimals)).to_i
          uint(scaled_value, byte_size)
        end

        # Properly encodes signed fixed-point numbers.
        def fixed(value, byte_size, decimals)
          raise ArgumentError, "Don't know how to handle this input." unless value.is_a? Numeric
          raise ValueOutOfBounds, value unless value >= -2 ** (decimals - 1) and value < 2 ** (decimals - 1)
          scaled_value = (value * (10 ** decimals)).to_i
          int(scaled_value, byte_size)
        end

        # Properly encodes byte(-string)s.
        def bytes(value, length)
          raise EncodingError, "Expecting String: #{value}" unless value.instance_of? String
          value = handle_hex_string value, length
          raise ArgumentError, "Value must be a string of length #{length}" unless value.is_a?(String) && value.bytesize == length
          value.b
        end

        # Properly encodes (byte-)strings.
        def string(value)
          raise ArgumentError, "Value must be a string" unless value.is_a?(String)
          value.b
        end

        # Properly encodes tuples.
        def tuple(types, values)
          Abi.solidity_packed(types, values)
        end

        # Properly encodes hash-strings.
        def hash(value, byte_size)
          raise EncodingError, "Argument too long: #{value}" unless byte_size > 0 and byte_size <= 32
          hash_bytes = handle_hex_string value, byte_size
          hash_bytes.b
        end

        # Properly encodes addresses.
        def address(value)
          if value.is_a? Address

            # from checksummed address with 0x prefix
            Util.zpad_hex value.to_s[2..-1], 20
          elsif value.is_a? Integer

            # address from integer
            Util.zpad_int value, 20
          elsif value.size == 20

            # address from encoded address
            Util.zpad value, 20
          elsif value.size == 40

            # address from hexadecimal address
            Util.zpad_hex value, 20
          elsif value.size == 42 and value[0, 2] == "0x"

            # address from hexadecimal address with 0x prefix
            Util.zpad_hex value[2..-1], 20
          else
            raise EncodingError, "Could not parse address: #{value}"
          end
        end

        # Properly encodes dynamic-sized arrays.
        def array(type, values)
          values.map { |value| type(type, value) }.join.b
        end

        # Properly encodes fixed-size arrays.
        def fixed_array(type, values, size)
          raise ArgumentError, "Array size does not match" unless values.size == size
          array(type, values)
        end

        # The ABI encoder needs to be able to determine between a hex `"123"`
        # and a binary `"123"` string.
        def handle_hex_string(val, len)
          if Util.prefixed? val or
             (len === val.size / 2 and Util.hex? val)

            # There is no way telling whether a string is hex or binary with certainty
            # in Ruby. Therefore, we assume a `0x` prefix to indicate a hex string.
            # Additionally, if the string size is exactly the double of the expected
            # binary size, we can assume a hex value.
            Util.hex_to_bin val
          else

            # Everything else will be assumed binary or raw string.
            val.b
          end
        end
      end
    end
  end
end


================================================
FILE: lib/eth/abi/type.rb
================================================
# Copyright (c) 2016-2025 The Ruby-Eth Contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# -*- encoding : ascii-8bit -*-

# Provides the {Eth} module.
module Eth

  # Provides a Ruby implementation of the Ethereum Application Binary Interface (ABI).
  module Abi

    # Provides a class to handle and parse common ABI types.
    class Type

      # Provides a specific parser error if type cannot be determined.
      class ParseError < StandardError; end

      # The base attribute, e.g., `string` or `bytes`.
      attr :base_type

      # The sub-type attribute, e.g., `256` as size of an uint256.
      attr :sub_type

      # The dimension attribute, e.g., `[10]` for an array of size 10.
      attr :dimensions

      # The components of a tuple type.
      attr :components

      # The name of tuple component.
      attr :name

      # Create a new Type object for base types, sub types, and dimensions.
      # Should not be used; use {Type.parse} instead.
      #
      # @param base_type [String] the base-type attribute.
      # @param sub_type [String] the sub-type attribute.
      # @param dimensions [Array] the dimension attribute.
      # @param components [Array] the components attribute.
      # @param component_name [String] the tuple component's name.
      # @return [Eth::Abi::Type] an ABI type object.
      def initialize(base_type, sub_type, dimensions, components = nil, component_name = nil)
        sub_type = sub_type.to_s
        @base_type = base_type
        @sub_type = sub_type
        @dimensions = dimensions
        @components = components
        @name = component_name
      end

      # Converts the self.parse method into a constructor.
      konstructor :parse

      # Attempts to parse a string containing a common Solidity type.
      # Creates a new Type upon success (using konstructor).
      #
      # @param type [String] a common Solidity type.
      # @param components [Array] the components attribute.
      # @param component_name [String] the tuple component's name.
      # @return [Eth::Abi::Type] a parsed Type object.
      # @raise [ParseError] if it fails to parse the type.
      def parse(type, components = nil, component_name = nil)
        if type.is_a?(Type)
          @base_type = type.base_type
          @sub_type = type.sub_type
          @dimensions = type.dimensions
          @components = type.components
          @name = type.name
          return
        end

        # ensure the type string is reasonable before attempting to parse
        raise ParseError, "Invalid type format" unless type.is_a? String

        if type.start_with?("tuple(") || type.start_with?("(")
          tuple_str = type.start_with?("tuple(") ? type : "tuple#{type}"
          inner, rest = extract_tuple(tuple_str)
          inner_types = split_tuple_types(inner)
          inner_types.each { |t| Type.parse(t) }
          base_type = "tuple"
          sub_type = ""
          dimension = rest
          components ||= inner_types.map { |t| { "type" => t } }
        else
          match = /\A([a-z]+)([0-9]*x?[0-9]*)((?:\[\d+\]|\[\])*)\z/.match(type)
          raise ParseError, "Invalid type format" unless match
          _, base_type, sub_type, dimension = match.to_a
          sub_type = "256" if %w[uint int].include?(base_type) && sub_type.empty?
        end

        # type dimension can only be numeric or empty for dynamic arrays
        dims = dimension.scan(/\[\d+\]|\[\]/)
        raise ParseError, "Unknown characters found in array declaration" if dims.join != dimension

        # enforce base types
        validate_base_type base_type, sub_type

        # return a new Type (using konstructor)
        sub_type = sub_type.to_s
        @base_type = base_type
        @sub_type = sub_type
        @dimensions = dims.map { |x| x == "[]" ? 0 : x[1...-1].to_i }
        @components = components.map { |component| Abi::Type.parse(component["type"], component.dig("components"), component.dig("name")) } if components&.any?
        @name = component_name
      end

      # Creates a new uint256 type used for size.
      #
      # @return [Eth::Abi::Type] a uint256 size type.
      def self.size_type
        @size_type ||= new("uint", 256, [])
      end

      # Compares two types for their attributes.
      #
      # @param another_type [Eth::Abi::Type] another type to be compared.
      # @return [Boolean] true if all attributes match.
      def ==(another_type)
        base_type == another_type.base_type and
          sub_type == another_type.sub_type and
          dimensions == another_type.dimensions
      end

      # Computes the size of a type if possible.
      #
      # @return [Integer] the size of the type; or nil if not available.
      def size
        s = nil
        if dimensions.empty?
          if !(["string", "bytes", "tuple"].include?(base_type) and sub_type.empty?)
            s = 32
          elsif base_type == "tuple" and components&.none?(&:dynamic?)
            s = components.sum(&:size)
          end
        elsif dimensions.last != 0 and !nested_sub.dynamic?
          s = dimensions.last * nested_sub.size
        end
        @size ||= s
      end

      # Helpes to determine whether array is of dynamic size.
      #
      # @return [Boolean] true if array is of dynamic size.
      def dynamic?
        size.nil?
      end

      # Types can have nested sub-types in arrays.
      #
      # @return [Eth::Abi::Type] nested sub-type.
      def nested_sub
        @nested_sub ||= self.class.new(base_type, sub_type, dimensions[0...-1], components, name)
      end

      # Allows exporting the type as string.
      #
      # @return [String] the type string.
      def to_s
        if base_type == "tuple"
          "(" + components.map(&:to_s).join(",") + ")" + (dimensions.size > 0 ? dimensions.map { |x| "[#{x == 0 ? "" : x}]" }.join : "")
        elsif dimensions.empty?
          if %w[string bytes].include?(base_type) and sub_type.empty?
            base_type
          else
            "#{base_type}#{sub_type}"
          end
        else
          "#{base_type}#{sub_type}#{dimensions.map { |x| "[#{x == 0 ? "" : x}]" }.join}"
        end
      end

      private

      # Validates all known base types and raises if an issue occurs.
      def validate_base_type(base_type, sub_type)
        case base_type
        when "string"

          # string can not have any suffix
          raise ParseError, "String type must have no suffix or numerical suffix" unless sub_type.empty?
        when "bytes"

          # bytes can be no longer than 32 bytes
          raise ParseError, "Maximum 32 bytes for fixed-length string or bytes" unless sub_type.empty? or (sub_type.to_i <= 32 and sub_type.to_i > 0)
        when "tuple"

          # tuples can not have any suffix
          raise ParseError, "Tuple type must have no suffix or numerical suffix" unless sub_type.empty?
        when "uint", "int"

          # integers must have a numerical suffix
          raise ParseError, "Integer type must have numerical suffix" unless sub_type =~ /\A[0-9]+\z/

          # integer size must be valid
          size = sub_type.to_i
          raise ParseError, "Integer size out of bounds" unless size >= 8 and size <= 256
          raise ParseError, "Integer size must be multiple of 8" unless size % 8 == 0
        when "ureal", "real", "fixed", "ufixed"

          # floats must have valid dimensional suffix
          raise ParseError, "Real type must have suffix of form <size>x<decimals>, e.g. 128x128" unless sub_type =~ /\A[0-9]+x[0-9]+\z/
          size, decimals = sub_type.split("x").map(&:to_i)
          total = size + decimals
          raise ParseError, "Real size out of bounds (max 32 bytes)" unless total >= 8 and total <= 256
          raise ParseError, "Real size must be multiples of 8" unless size % 8 == 0
        when "hash"

          # hashs must have numerical suffix
          raise ParseError, "Hash type must have numerical suffix" unless sub_type =~ /\A[0-9]+\z/
        when "address"

          # addresses cannot have any suffix
          raise ParseError, "Address cannot have suffix" unless sub_type.empty?
        when "bool"

          # booleans cannot have any suffix
          raise ParseError, "Bool cannot have suffix" unless sub_type.empty?
        else

          # we cannot parse arbitrary types such as 'decimal' or 'hex'
          raise ParseError, "Unknown base type"
        end
      end

      # Extracts the inner type list and trailing dimensions from an inline tuple definition.
      def extract_tuple(type)
        idx = 6 # skip "tuple("
        depth = 1
        while idx < type.length && depth > 0
          case type[idx]
          when "("
            depth += 1
          when ")"
            depth -= 1
          end
          idx += 1
        end
        raise ParseError, "Invalid tuple format" unless depth.zero?
        inner = type[6...(idx - 1)]
        rest = type[idx..] || ""
        [inner, rest]
      end

      # Splits a tuple component list into individual type strings, handling nested tuples.
      def split_tuple_types(str)
        types = []
        depth = 0
        current = ""
        str.each_char do |ch|
          case ch
          when "("
            depth += 1
            current << ch
          when ")"
            depth -= 1
            current << ch
          when ","
            if depth.zero?
              types << current
              current = ""
            else
              current << ch
            end
          else
            current << ch
          end
        end
        types << current unless current.empty?
        types
      end
    end
  end
end


================================================
FILE: lib/eth/abi.rb
================================================
# Copyright (c) 2016-2025 The Ruby-Eth Contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# -*- encoding : ascii-8bit -*-

require "konstructor"

# Provides the {Eth} module.
module Eth

  # Provides a Ruby implementation of the Ethereum Application Binary Interface (ABI).
  # ref: https://docs.soliditylang.org/en/develop/abi-spec.html
  module Abi
    extend self

    # Provides a special encoding error if anything fails to encode.
    class EncodingError < StandardError; end

    # Provides a special decoding error if anything fails to decode.
    class DecodingError < StandardError; end

    # Provides a special out-of-bounds error for values.
    class ValueOutOfBounds < StandardError; end

    # Encodes Application Binary Interface (ABI) data. It accepts multiple
    # arguments and encodes using the head/tail mechanism.
    #
    # @param types [Array] types to be ABI-encoded.
    # @param args [Array] values to be ABI-encoded.
    # @param packed [Bool] set true to return packed encoding (default: `false`).
    # @return [String] the encoded ABI data.
    def encode(types, args, packed = false)
      return solidity_packed(types, args) if packed
      types = [types] unless types.instance_of? Array
      args = [args] unless args.instance_of? Array
      raise ArgumentError, "Types and values must be the same length" if types.length != args.length

      # parse all types
      parsed_types = types.map { |t| Type === t ? t : Type.parse(t) }

      # prepare the "head"
      head_size = (0...args.size)
        .map { |i| parsed_types[i].size or 32 }
        .reduce(0, &:+)
      head, tail = "", ""

      # encode types and arguments
      args.each_with_index do |arg, i|
        if parsed_types[i].dynamic?
          head += Abi::Encoder.type(Type.size_type, head_size + tail.size)
          tail += Abi::Encoder.type(parsed_types[i], arg)
        else
          head += Abi::Encoder.type(parsed_types[i], arg)
        end
      end

      # return the encoded ABI blob
      "#{head}#{tail}"
    end

    # Encodes Application Binary Interface (ABI) data in non-standard packed mode.
    # It accepts multiple arguments and encodes using the head/tail mechanism.
    #
    # @param types [Array] types to be ABI-encoded.
    # @param args [Array] values to be ABI-encoded.
    # @return [String] the encoded packed ABI data.
    # @raise [ArgumentError] if types and args are of different size.
    def solidity_packed(types, args)
      raise ArgumentError, "Types and values must be the same length" if types.length != args.length

      # We do not use the type system for packed encoding but want to call the parser once
      # to enforce the type validation.
      _ = types.map { |t| Type === t ? t : Type.parse(t) }

      packed = types.zip(args).map do |type, arg|
        Abi::Packed::Encoder.type(type, arg)
      end.join
      packed.force_encoding(Encoding::ASCII_8BIT)
    end

    # Decodes Application Binary Interface (ABI) data. It accepts multiple
    # arguments and decodes using the head/tail mechanism.
    #
    # @param types [Array] the ABI to be decoded.
    # @param data [String] ABI data to be decoded.
    # @return [Array] the decoded ABI data.
    def decode(types, data)

      # accept hex abi but decode it first
      data = Util.hex_to_bin data if Util.hex? data

      # parse all types
      parsed_types = types.map { |t| Type.parse(t) }

      # prepare output data
      outputs = [nil] * types.size
      start_positions = [nil] * types.size + [data.size]
      pos = 0
      parsed_types.each_with_index do |t, i|
        if t.dynamic?

          # record start position for dynamic type
          start_positions[i] = Util.deserialize_big_endian_to_int(data[pos, 32])
          j = i - 1
          while j >= 0 and start_positions[j].nil?
            start_positions[j] = start_positions[i]
            j -= 1
          end
          pos += 32
        else

          # get data directly for static types
          outputs[i] = data[pos, t.size]
          pos += t.size
        end
      end

      # add start position equal the length of the entire data
      j = types.size - 1
      while j >= 0 and start_positions[j].nil?
        start_positions[j] = start_positions[types.size]
        j -= 1
      end
      raise DecodingError, "Not enough data for head" unless pos <= data.size

      # add dynamic types
      parsed_types.each_with_index do |t, i|
        if t.dynamic?
          offset, next_offset = start_positions[i, 2]
          outputs[i] = data[offset...next_offset]
        end
      end

      # return the decoded ABI types and data
      parsed_types.zip(outputs).map { |(type, out)| Abi::Decoder.type(type, out) }
    end
  end
end

require "eth/abi/packed/encoder"
require "eth/abi/decoder"
require "eth/abi/encoder"
require "eth/abi/event"
require "eth/abi/function"
require "eth/abi/type"


================================================
FILE: lib/eth/address.rb
================================================
# Copyright (c) 2016-2025 The Ruby-Eth Contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Provides the {Eth} module.
module Eth

  # The {Eth::Address} class to handle checksummed Ethereum addresses.
  class Address

    # The literal zero address 0x0.
    ZERO = "0x0000000000000000000000000000000000000000"

    # Provides a special checksum error if EIP-55 is violated.
    class CheckSumError < StandardError; end

    # The prefixed and checksummed Ethereum address.
    attr_reader :address

    # Constructor of the {Eth::Address} class. Creates a new hex
    # prefixed address.
    #
    # @param address [String] hex string representing an ethereum address.
    def initialize(address)
      unless Util.hex? address
        raise CheckSumError, "Unknown address type #{address}!"
      end
      @address = Util.prefix_hex address
      unless self.valid?
        raise CheckSumError, "Invalid address provided #{address}"
      end
    end

    # Checks that the address is valid.
    #
    # @return [Boolean] true if valid address.
    def valid?
      if !matches_any_format?
        false
      elsif not_checksummed?
        true
      else
        checksum_matches?
      end
    end

    # Checks that the address is the zero address.
    #
    # @return [Boolean] true if the address is the zero address.
    def zero?
      address == ZERO
    end

    # Generate a checksummed address.
    #
    # @return [String] prefixed hexstring representing an checksummed address.
    def checksummed
      raise CheckSumError, "Invalid address: #{address}" unless matches_any_format?

      cased = unprefixed.chars.zip(checksum.chars).map do |char, check|
        check.match(/[0-7]/) ? char.downcase : char.upcase
      end

      Util.prefix_hex cased.join
    end

    alias :to_s :checksummed

    private

    # Checks whether the address checksum matches.
    def checksum_matches?
      address == checksummed
    end

    # Checks whether the address is not checksummed.
    def not_checksummed?
      all_uppercase? || all_lowercase?
    end

    # Checks whether the address is all upper-case.
    def all_uppercase?
      address.match /(?:0[xX])[A-F0-9]{40}/
    end

    # Checks whether the address is all lower-case.
    def all_lowercase?
      address.match /(?:0[xX])[a-f0-9]{40}/
    end

    # Checks whether the address matches any known format.
    def matches_any_format?
      address.match /\A(?:0[xX])[a-fA-F0-9]{40}\z/
    end

    # Computes the checksum of the address.
    def checksum
      Util.bin_to_hex Util.keccak256 unprefixed.downcase
    end

    # Removes the hex prefix.
    def unprefixed
      Util.remove_hex_prefix address
    end
  end
end


================================================
FILE: lib/eth/api.rb
================================================
# Copyright (c) 2016-2025 The Ruby-Eth Contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Provides the {Eth} module.
module Eth

  # Provides the `Eth::Api` module grouping known RPC commands.
  module Api

    # Implements the available RPC-APIs provided by Geth version 1.10.26.
    COMMANDS = [
      "account_ecRecover",
      "account_new",
      "account_signData",
      "account_signTransaction",
      "account_signTypedData",
      "admin_addPeer",
      "admin_addTrustedPeer",
      "admin_clearHistory",
      "admin_datadir",
      "admin_exportChain",
      "admin_getDatadir",
      "admin_getNodeInfo",
      "admin_getPeers",
      "admin_importChain",
      "admin_nodeInfo",
      "admin_peerEvents",
      "admin_peers",
      "admin_removePeer",
      "admin_removeTrustedPeer",
      "admin_sleep",
      "admin_sleepBlocks",
      "admin_startHTTP",
      "admin_startRPC",
      "admin_startWS",
      "admin_stopHTTP",
      "admin_stopRPC",
      "admin_stopWS",
      "clef_deriveAccount",
      "clef_listWallets",
      "clef_openWallet",
      "clique_discard",
      "clique_getSigner",
      "clique_getSigners",
      "clique_getSignersAtHash",
      "clique_getSnapshot",
      "clique_getSnapshotAtHash",
      "clique_proposals",
      "clique_propose",
      "clique_status",
      "db_getHex",
      "db_getString",
      "db_putHex",
      "db_putString",
      "debug_accountRange",
      "debug_backtraceAt",
      "debug_blockProfile",
      "debug_chaindbCompact",
      "debug_chaindbProperty",
      "debug_cpuProfile",
      "debug_dbAncient",
      "debug_dbAncients",
      "debug_dbGet",
      "debug_dumpBlock",
      "debug_freeOSMemory",
      "debug_freezeClient",
      "debug_gcStats",
      "debug_getAccessibleState",
      "debug_getBadBlocks",
      "debug_getBlockRlp",
      "debug_getHeaderRlp",
      "debug_getModifiedAccountsByHash",
      "debug_getModifiedAccountsByNumber",
      "debug_getRawBlock",
      "debug_getRawHeader",
      "debug_getRawReceipts",
      "debug_getRawTransaction",
      "debug_getTrieFlushInterval",
      "debug_goTrace",
      "debug_intermediateRoots",
      "debug_memStats",
      "debug_mutexProfile",
      "debug_preimage",
      "debug_printBlock",
      "debug_seedHash",
      "debug_setBlockProfileRate",
      "debug_setGCPercent",
      "debug_setHead",
      "debug_setMutexProfileFraction",
      "debug_setTrieFlushInterval",
      "debug_stacks",
      "debug_standardTraceBadBlockToFile",
      "debug_standardTraceBlockToFile",
      "debug_startCPUProfile",
      "debug_startGoTrace",
      "debug_stopCPUProfile",
      "debug_stopGoTrace",
      "debug_storageRangeAt",
      "debug_subscribe",
      "debug_traceBadBlock",
      "debug_traceBlock",
      "debug_traceBlockByHash",
      "debug_traceBlockByNumber",
      "debug_traceBlockFromFile",
      "debug_traceCall",
      "debug_traceChain",
      "debug_traceTransaction",
      "debug_verbosity",
      "debug_vmodule",
      "debug_writeBlockProfile",
      "debug_writeMemProfile",
      "debug_writeMutexProfile",
      "dev_addWithdrawal",
      "dev_setFeeRecipient",
      "eth_accounts",
      "eth_blobBaseFee",
      "eth_blockNumber",
      "eth_call",
      "eth_chainId",
      "eth_coinbase",
      "eth_compile",
      "eth_compileLLL",
      "eth_compileSerpent",
      "eth_compileSolidity",
      "eth_contract",
      "eth_createAccessList",
      "eth_defaultAccount",
      "eth_defaultBlock",
      "eth_estimateGas",
      "eth_feeHistory",
      "eth_fillTransaction",
      "eth_filter",
      "eth_gasPrice",
      "eth_getAccounts",
      "eth_getBalance",
      "eth_getBlobBaseFee",
      "eth_getBlock",
      "eth_getBlockByHash",
      "eth_getBlockByNumber",
      "eth_getBlockNumber",
      "eth_getBlockReceipts",
      "eth_getBlockTransactionCount",
      "eth_getBlockTransactionCountByHash",
      "eth_getBlockTransactionCountByNumber",
      "eth_getBlockUncleCount",
      "eth_getCode",
      "eth_getCoinbase",
      "eth_getCompilers",
      "eth_getFilterChanges",
      "eth_getFilterLogs",
      "eth_getGasPrice",
      "eth_getHashrate",
      "eth_getHeaderByHash",
      "eth_getHeaderByNumber",
      "eth_getLogs",
      "eth_getMaxPriorityFeePerGas",
      "eth_getMining",
      "eth_getPendingTransactions",
      "eth_getProof",
      "eth_getProtocolVersion",
      "eth_getRawTransaction",
      "eth_getRawTransactionFromBlock",
      "eth_getStorageAt",
      "eth_getSyncing",
      "eth_getTransaction",
      "eth_getTransactionByBlockHashAndIndex",
      "eth_getTransactionByBlockNumberAndIndex",
      "eth_getTransactionByHash",
      "eth_getTransactionCount",
      "eth_getTransactionFromBlock",
      "eth_getTransactionReceipt",
      "eth_getUncle",
      "eth_getUncleByBlockHashAndIndex",
      "eth_getUncleByBlockNumberAndIndex",
      "eth_getUncleCountByBlockHash",
      "eth_getUncleCountByBlockNumber",
      "eth_getWork",
      "eth_hashrate",
      "eth_iban",
      "eth_icapNamereg",
      "eth_isSyncing",
      "eth_maxPriorityFeePerGas",
      "eth_mining",
      "eth_namereg",
      "eth_newBlockFilter",
      "eth_newFilter",
      "eth_newPendingTransactionFilter",
      "eth_pendingTransactions",
      "eth_protocolVersion",
      "eth_resend",
      "eth_sendIBANTransaction",
      "eth_sendRawTransaction",
      "eth_sendTransaction",
      "eth_sign",
      "eth_signTransaction",
      "eth_simulateV1",
      "eth_submitHashrate",
      "eth_submitTransaction",
      "eth_submitWork",
      "eth_syncing",
      "eth_uninstallFilter",
      "eth_unsubscribe",
      "les_addBalance",
      "les_clientInfo",
      "les_getCheckpoint",
      "les_getCheckpointContractAddress",
      "les_latestCheckpoint",
      "les_priorityClientInfo",
      "les_serverInfo",
      "les_setClientParams",
      "les_setDefaultParams",
      "miner_getHashrate",
      "miner_setEtherbase",
      "miner_setExtra",
      "miner_setGasLimit",
      "miner_setGasPrice",
      "miner_setRecommitInterval",
      "miner_start",
      "miner_stop",
      "net_getListening",
      "net_getPeerCount",
      "net_getVersion",
      "net_listening",
      "net_peerCount",
      "net_version",
      "personal_deriveAccount",
      "personal_ecRecover",
      "personal_importRawKey",
      "personal_initializeWallet",
      "personal_initializeWallets",
      "personal_listAccounts",
      "personal_listWallets",
      "personal_lockAccount",
      "personal_newAccount",
      "personal_openWallet",
      "personal_sendTransaction",
      "personal_sign",
      "personal_signTransaction",
      "personal_unlockAccount",
      "personal_unpair",
      "rpc_getModules",
      "rpc_modules",
      "shh_addToGroup",
      "shh_getFilterChanges",
      "shh_getMessages",
      "shh_hasIdentity",
      "shh_newFilter",
      "shh_newGroup",
      "shh_newIdentity",
      "shh_post",
      "shh_uninstallFilter",
      "shh_version",
      "txpool_content",
      "txpool_contentFrom",
      "txpool_getContent",
      "txpool_getInspect",
      "txpool_getStatus",
      "txpool_inspect",
      "txpool_status",
      "web3_admin",
      "web3_bzz",
      "web3_clientVersion",
      "web3_createBatch",
      "web3_currentProvider",
      "web3_db",
      "web3_debug",
      "web3_dev",
      "web3_eth",
      "web3_fromAscii",
      "web3_fromDecimal",
      "web3_fromICAP",
      "web3_fromUtf8",
      "web3_fromWei",
      "web3_isAddress",
      "web3_isChecksumAddress",
      "web3_isConnected",
      "web3_isIBAN",
      "web3_miner",
      "web3_net",
      "web3_padLeft",
      "web3_padRight",
      "web3_personal",
      "web3_providers",
      "web3_reset",
      "web3_rpc",
      "web3_setProvider",
      "web3_settings",
      "web3_sha3",
      "web3_shh",
      "web3_toAscii",
      "web3_toChecksumAddress",
      "web3_toDecimal",
      "web3_toHex",
      "web3_toUtf8",
      "web3_toWei",
      "web3_txpool",
      "web3_version",
    ]
  end
end


================================================
FILE: lib/eth/bls.rb
================================================
# frozen_string_literal: true

require "bls"

module Eth
  # Helper methods for interacting with BLS12-381 points and signatures
  module Bls
    module_function

    # Decode a compressed G1 public key from hex.
    # @param [String] hex a compressed G1 point
    # @return [BLS::PointG1]
    def decode_public_key(hex)
      BLS::PointG1.from_hex Util.remove_hex_prefix(hex)
    end

    # Encode a G1 public key to compressed hex.
    # @param [BLS::PointG1] point
    # @return [String] hex string prefixed with 0x
    def encode_public_key(point)
      Util.prefix_hex point.to_hex(compressed: true)
    end

    # Decode a compressed G2 signature from hex.
    # @param [String] hex a compressed G2 point
    # @return [BLS::PointG2]
    def decode_signature(hex)
      BLS::PointG2.from_hex Util.remove_hex_prefix(hex)
    end

    # Encode a G2 signature to compressed hex.
    # @param [BLS::PointG2] point
    # @return [String] hex string prefixed with 0x
    def encode_signature(point)
      Util.prefix_hex point.to_hex(compressed: true)
    end

    # Derive a compressed public key from a private key.
    # @param [String] priv_hex private key as hex
    # @return [String] compressed G1 public key (hex)
    def get_public_key(priv_hex)
      key = BLS.get_public_key Util.remove_hex_prefix(priv_hex)
      encode_public_key key
    end

    # Sign a message digest with the given private key.
    # @param [String] message message digest (hex)
    # @param [String] priv_hex private key as hex
    # @return [String] compressed G2 signature (hex)
    def sign(message, priv_hex)
      sig = BLS.sign Util.remove_hex_prefix(message),
                     Util.remove_hex_prefix(priv_hex)
      encode_signature sig
    end

    # Verify a BLS signature using pairings. This mirrors the behaviour of
    # the BLS12-381 pairing precompile.
    # @param [String] message message digest (hex)
    # @param [String] signature_hex compressed G2 signature (hex)
    # @param [String] pubkey_hex compressed G1 public key (hex)
    # @return [Boolean] verification result
    def verify(message, signature_hex, pubkey_hex)
      signature = decode_signature(signature_hex)
      pubkey = decode_public_key(pubkey_hex)
      BLS.verify(signature, Util.remove_hex_prefix(message), pubkey)
    end
  end
end


================================================
FILE: lib/eth/chain.rb
================================================
# Copyright (c) 2016-2025 The Ruby-Eth Contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Provides the {Eth} module.
module Eth

  # Encapsulates {Eth::Chain} IDs and utilities for EIP-155 compatibility.
  # Ref: https://eips.ethereum.org/EIPS/eip-155
  module Chain
    extend self

    # Provides a special replay protection error if EIP-155 is violated.
    class ReplayProtectionError < StandardError; end

    # Chain ID for Ethereum mainnet.
    ETHEREUM = 1.freeze

    # Chain ID for Expanse mainnet.
    EXPANSE = 2.freeze

    # Chain ID for Optimistic Ethereum mainnet.
    OPTIMISM = 10.freeze

    # Chain ID for Cronos mainnet.
    CRONOS = 25.freeze

    # Chain ID for Rootstock mainnet.
    RSK = 30.freeze

    # Chain ID for BNB Smart Chain mainnet.
    BNB = 56.freeze

    # Chain ID for Ethereum Classic mainnet.
    CLASSIC = 61.freeze

    # Chain ID for POA Network mainnet.
    POA_NET = 99.freeze

    # Chain ID for xDAI mainnet (now Gnosis Chain).
    XDAI = 100.freeze

    # Chain ID for Gnosis mainnet (formerly xDAI).
    GNOSIS = XDAI.freeze

    # Chain ID for the Matic mainnet (now Polygon).
    MATIC = 137.freeze

    # Chain ID for the Polygon mainnet (formerly Matic).
    POLYGON = MATIC.freeze

    # Chain ID for Filecoin mainnet.
    FILECOIN = 314.freeze

    # Chain ID for the Cronos zkEVM chain.
    CRONOS_ZK = 388.freeze

    # Chain ID for Redstone Optimistic Rollup.
    REDSTONE = 690.freeze

    # Chain ID for the Polygon zkEVM.
    POLYGON_ZK = 1101.freeze

    # Chain ID for the Lisk layer 2.
    LISK = 1135.freeze

    # Chain ID for Moonbeam
    MOONBEAM = 1284.freeze

    # Chain ID for Base mainnet.
    BASE = 8453.freeze

    # Chain ID for the EVMOS mainnet.
    EVMOS = 9001.freeze

    # Chain ID for the Celo layer 2.
    CELO = 42220.freeze

    # Chain ID for Arbitrum One mainnet.
    ARBITRUM = 42161.freeze

    # Chain ID for Avalance C-Chain mainnet.
    AVALANCHE = 43114.freeze

    # Chain ID for Linea mainnet.
    LINEA = 59144.freeze

    # Chain ID for the Scroll layer 2.
    SCROLL = 534352.freeze

    # Chain ID for Morden (Ethereum) testnet.
    MORDEN = 2.freeze

    # Chain ID for Ropsten testnet.
    ROPSTEN = 3.freeze

    # Chain ID for Rinkeby testnet.
    RINKEBY = 4.freeze

    # Chain ID for Goerli testnet.
    GOERLI = 5.freeze

    # Chain ID for Kotti testnet.
    KOTTI = 6.freeze

    # Chain ID for Kovan testnet.
    KOVAN = 42.freeze

    # Chain ID for Morden (Classic) testnet.
    MORDEN_CLASSIC = 62.freeze

    # Chain ID for Mordor testnet.
    MORDOR = 63.freeze

    # Chain ID for Optimistm Kovan testnet.
    KOVAN_OPTIMISM = 69.freeze

    # Chain ID for Arbitrum xDAI testnet.
    XDAI_ARBITRUM = 200.freeze

    # Chain ID for Optimistic Goerli testnet.
    GOERLI_OPTIMISM = 420.freeze

    # Chain ID for Moonriver testnet
    MOONRIVER = 1285.freeze

    # Chain ID for Moonbase alpha
    MOONBASE = 1287.freeze

    # Chain ID for the Garnet Holesky testnet
    GARNET = 17069.freeze

    # Chain ID for the Polygon Mumbai testnet.
    MUMBAI = 80001.freeze

    # Chain ID for Arbitrum Rinkeby testnet.
    RINKEBY_ARBITRUM = 421611.freeze

    # Chain ID for Arbitrum Goerli testnet.
    GOERLI_ARBITRUM = 421613.freeze

    # Chain ID for Hoodi testnet.
    HOODI = 560048.freeze

    # Chain ID for Sepolia testnet.
    SEPOLIA = 11155111.freeze

    # Chain ID for Holesovice testnet.
    HOLESOVICE = 11166111.freeze

    # Chain ID for Holesovice testnet.
    HOLESKY = HOLESOVICE

    # Chain ID for Basecamp testnet.
    BASECAMP = 123420001114.freeze

    # Chain ID for the geth private network preset.
    PRIVATE_GETH = 1337.freeze

    # Indicates wether the given `v` indicates a legacy chain value
    # used by ledger wallets without EIP-155 replay protection.
    #
    # @param v [Integer] the signature's `v` value.
    # @return [Boolean] true if ledger's legacy value.
    def ledger?(v)
      [0, 1].include? v
    end

    # Indicates wether the given `v` indicates a legacy chain value
    # without EIP-155 replay protection.
    #
    # @param v [Integer] the signature's `v` value.
    # @return [Boolean] true if legacy value.
    def legacy?(v)
      [27, 28].include? v
    end

    # Convert a given `v` value to an ECDSA recovery id for the given
    # EIP-155 chain ID.
    #
    # @param v [Integer] the signature's `v` value.
    # @param chain_id [Integer] the chain id the signature was generated on.
    # @return [Integer] the recovery id corresponding to `v`.
    # @raise [ReplayProtectionError] if the given `v` is invalid.
    def to_recovery_id(v, chain_id = ETHEREUM)
      e = 0 + 2 * chain_id + 35
      i = 1 + 2 * chain_id + 35
      if ledger? v

        # some wallets are using a `v` of 0 or 1 (ledger)
        return v
      elsif legacy? v

        # this is the pre-EIP-155 legacy case
        return v - 27
      elsif [e, i].include? v

        # this is the EIP-155 case
        return v - 35 - 2 * chain_id
      else
        raise ReplayProtectionError, "Invalid v #{v} value for chain ID #{chain_id}. Invalid chain ID?"
      end
    end

    # Converts a recovery ID into the expected `v` on a given chain.
    #
    # @param recovery_id [Integer] signature recovery id.
    # @param chain_id [Integer] the chain id the signature was generated on.
    # @return [Integer] the signature's `v` value.
    def to_v(recovery_id, chain_id = nil)
      if chain_id.nil? or chain_id < 1
        v = 27 + recovery_id
      else
        v = 2 * chain_id + 35 + recovery_id
      end
      return v
    end

    # Converts a `v` value into a chain ID. This does not work for legacy signatures
    # with `v < 36` that do not conform with EIP-155.
    #
    # @param v [Integer] the signature's `v` value.
    # @return [Integer] the chain id as per EIP-155 or `nil` if there is no replay protection.
    def to_chain_id(v)
      return nil if v < 36
      chain_id = (v - 35) / 2
      return nil if chain_id < 1
      return chain_id
    end
  end
end


================================================
FILE: lib/eth/client/http.rb
================================================
# Copyright (c) 2016-2025 The Ruby-Eth Contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require "uri"
require "httpx"

# Provides the {Eth} module.
module Eth

  # Provides an HTTP/S-RPC client with basic authentication.
  class Client::Http < Client

    # The host of the HTTP endpoint.
    attr_reader :host

    # The port of the HTTP endpoint.
    attr_reader :port

    # The full URI of the HTTP endpoint, including path.
    attr_reader :uri

    # Attribute indicator for SSL.
    attr_reader :ssl

    # Attribute for user.
    attr_reader :user

    # Constructor for the HTTP Client. Should not be used; use
    # {Client.create} instead.
    #
    # @param host [String] an URI pointing to an HTTP RPC-API.
    def initialize(host)
      super
      uri = URI.parse(host)
      raise ArgumentError, "Unable to parse the HTTP-URI!" unless ["http", "https"].include? uri.scheme
      @host = uri.host
      @port = uri.port
      @ssl = uri.scheme == "https"
      if !(uri.user.nil? && uri.password.nil?)
        @user = uri.user
        @password = uri.password
        if uri.query
          @uri = URI("#{uri.scheme}://#{uri.user}:#{uri.password}@#{@host}:#{@port}#{uri.path}?#{uri.query}")
        else
          @uri = URI("#{uri.scheme}://#{uri.user}:#{uri.password}@#{@host}:#{@port}#{uri.path}")
        end
      else
        @uri = uri
      end
      @client = HTTPX.plugin(:persistent).with(headers: { "Content-Type" => "application/json" })
    end

    # Sends an RPC request to the connected HTTP client.
    #
    # @param payload [Hash] the RPC request parameters.
    # @return [String] a JSON-encoded response.
    def send_request(payload)
      response = @client.post(@uri, body: payload)
      response.body.to_s
    end
  end

  private

  # Attribute for password.
  attr_reader :password
end


================================================
FILE: lib/eth/client/ipc.rb
================================================
# Copyright (c) 2016-2025 The Ruby-Eth Contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require "socket"

# Provides the {Eth} module.
module Eth

  # Provides an IPC-RPC client.
  class Client::Ipc < Client

    # The path of the IPC socket.
    attr_accessor :path

    # Constructor for the IPC Client. Should not be used; use
    # {Client.create} instead.
    #
    # @param path [String] an URI pointing to an IPC RPC-API.
    def initialize(path)
      super
      @path = path
    end

    # Sends an RPC request to the connected IPC socket.
    #
    # @param payload [Hash] the RPC request parameters.
    # @return [String] a JSON-encoded response.
    def send_request(payload)
      socket = UNIXSocket.new(@path)
      socket.puts(payload)
      read = socket.recvmsg(nil)[0]
      until read.end_with?("\n")
        read = read << socket.recvmsg(nil)[0]
      end
      socket.close
      return read
    end
  end
end


================================================
FILE: lib/eth/client/ws.rb
================================================
# Copyright (c) 2016-2025 The Ruby-Eth Contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require "socket"
require "openssl"
require "uri"
require "base64"
require "securerandom"
require "digest/sha1"
require "thread"
require "ipaddr"

# Provides the {Eth} module.
module Eth

  # Provides a WS/S-RPC client with automatic reconnection support.
  class Client::Ws < Client

    # The host of the WebSocket endpoint.
    attr_reader :host

    # The port of the WebSocket endpoint.
    attr_reader :port

    # The full URI of the WebSocket endpoint, including path.
    attr_reader :uri

    # Attribute indicator for SSL.
    attr_reader :ssl

    # Constructor for the WebSocket client. Should not be used; use
    # {Client.create} instead.
    #
    # @param host [String] a URI pointing to a WebSocket RPC-API.
    def initialize(host)
      super
      @uri = URI.parse(host)
      raise ArgumentError, "Unable to parse the WebSocket-URI!" unless %w[ws wss].include?(@uri.scheme)
      @host = @uri.host
      @port = @uri.port
      @ssl = @uri.scheme == "wss"
      @path = build_path(@uri)
      @mutex = Mutex.new
      @socket = nil
      @fragments = nil
    end

    # Sends an RPC request to the connected WebSocket endpoint.
    #
    # @param payload [Hash] the RPC request parameters.
    # @return [String] a JSON-encoded response.
    def send_request(payload)
      attempts = 0
      begin
        attempts += 1
        @mutex.synchronize do
          ensure_socket
          write_frame(@socket, payload)
          return read_message(@socket)
        end
      rescue IOError, SystemCallError => e
        @mutex.synchronize { close_socket }
        retry if attempts < 2
        raise e
      end
    end

    # Closes the underlying WebSocket connection.
    #
    # @return [void]
    def close
      @mutex.synchronize { close_socket }
    end

    private

    def ensure_socket
      return if @socket && !@socket.closed?

      socket = open_socket
      begin
        perform_handshake(socket)
        @socket = socket
        @fragments = nil
      rescue StandardError
        begin
          socket.close unless socket.closed?
        rescue IOError, SystemCallError
          nil
        end
        @socket = nil
        raise
      end
    end

    # Establishes the TCP socket for the RPC connection and upgrades it to TLS
    # when a secure endpoint is requested. TLS sessions enforce peer
    # verification, load the default system trust store, and enable hostname
    # verification when the current OpenSSL bindings support it.
    #
    # @return [TCPSocket, OpenSSL::SSL::SSLSocket] the established socket.
    # @raise [IOError, SystemCallError, OpenSSL::SSL::SSLError] if the socket
    #   cannot be opened or the TLS handshake fails.
    def open_socket
      tcp = TCPSocket.new(@host, @port)
      return tcp unless @ssl

      context = OpenSSL::SSL::SSLContext.new
      params = { verify_mode: OpenSSL::SSL::VERIFY_PEER }
      params[:verify_hostname] = true if context.respond_to?(:verify_hostname=)
      context.set_params(params)
      context.cert_store = OpenSSL::X509::Store.new.tap(&:set_default_paths)

      ssl_socket = OpenSSL::SSL::SSLSocket.new(tcp, context)
      ssl_socket.hostname = @host
      ssl_socket.sync_close = true
      ssl_socket.connect
      ssl_socket
    end

    def perform_handshake(socket)
      key = Base64.strict_encode64(SecureRandom.random_bytes(16))
      request = build_handshake_request(key)
      socket.write(request)
      response = read_handshake_response(socket)
      verify_handshake!(response, key)
    end

    def build_handshake_request(key)
      origin = build_origin_header
      host_header = build_host_header
      "GET #{@path} HTTP/1.1\r\n" \
      "Host: #{host_header}\r\n" \
      "Upgrade: websocket\r\n" \
      "Connection: Upgrade\r\n" \
      "Sec-WebSocket-Version: 13\r\n" \
      "Sec-WebSocket-Key: #{key}\r\n" \
      "Origin: #{origin}\r\n\r\n"
    end

    def read_handshake_response(socket)
      response = +""
      until response.end_with?("\r\n\r\n")
        chunk = socket.readpartial(1024)
        raise IOError, "Incomplete WebSocket handshake" if chunk.nil?
        response << chunk
      end
      response
    rescue EOFError
      raise IOError, "Incomplete WebSocket handshake"
    end

    def verify_handshake!(response, key)
      status_line = response.lines.first&.strip
      unless status_line&.start_with?("HTTP/1.1 101")
        raise IOError, "WebSocket handshake failed (status: #{status_line || "unknown"})"
      end

      accept = response[/Sec-WebSocket-Accept:\s*(.+)\r/i, 1]&.strip
      expected = Base64.strict_encode64(Digest::SHA1.digest("#{key}258EAFA5-E914-47DA-95CA-C5AB0DC85B11"))
      raise IOError, "WebSocket handshake failed (missing accept header)" unless accept
      raise IOError, "WebSocket handshake failed (invalid accept header)" unless accept == expected
    end

    def write_frame(socket, payload, opcode = 0x1)
      frame_payload = payload.is_a?(String) ? payload.dup : payload.to_s
      mask_key = SecureRandom.random_bytes(4)
      header = [0x80 | opcode]

      length = frame_payload.bytesize
      if length <= 125
        header << (0x80 | length)
      elsif length <= 0xFFFF
        header << (0x80 | 126)
        header.concat([length].pack("n").bytes)
      else
        header << (0x80 | 127)
        header.concat([length].pack("Q>").bytes)
      end

      masked_payload = apply_mask(frame_payload, mask_key)
      socket.write(header.pack("C*") + mask_key + masked_payload)
    end

    def read_message(socket)
      loop do
        frame = read_frame(socket)
        return frame if frame
      end
    end

    def read_frame(socket)
      header = read_bytes(socket, 2)
      byte1, byte2 = header.bytes
      opcode = byte1 & 0x0F
      masked = (byte2 & 0x80) == 0x80
      length = byte2 & 0x7F

      length = read_bytes(socket, 2).unpack1("n") if length == 126
      length = read_bytes(socket, 8).unpack1("Q>") if length == 127

      mask_key = masked ? read_bytes(socket, 4).bytes : nil
      payload = read_bytes(socket, length)
      payload_bytes = payload.bytes
      if mask_key
        payload_bytes.map!.with_index { |byte, index| byte ^ mask_key[index % 4] }
      end
      data = payload_bytes.pack("C*")

      case opcode
      when 0x0
        (@fragments ||= +"") << data
        if (byte1 & 0x80) == 0x80
          message = @fragments.dup
          @fragments = nil
          message
        else
          nil
        end
      when 0x1, 0x2
        if (byte1 & 0x80) == 0x80
          data
        else
          @fragments = data
          nil
        end
      when 0x8
        close_socket
        raise IOError, "WebSocket closed"
      when 0x9
        write_frame(socket, data, 0xA)
        nil
      when 0xA
        nil
      else
        nil
      end
    end

    def read_bytes(socket, length)
      data = +""
      while data.bytesize < length
        chunk = socket.read(length - data.bytesize)
        raise IOError, "Unexpected end of WebSocket stream" if chunk.nil? || chunk.empty?
        data << chunk
      end
      data
    end

    def apply_mask(payload, mask_key)
      mask_bytes = mask_key.bytes
      payload.bytes.map.with_index { |byte, index| byte ^ mask_bytes[index % 4] }.pack("C*")
    end

    def build_origin_header
      scheme = @ssl ? "https" : "http"
      host = format_origin_host(@uri.host)
      default_port = @ssl ? 443 : 80
      port = @uri.port
      port_suffix = port == default_port ? "" : ":#{port}"
      "#{scheme}://#{host}#{port_suffix}"
    end

    def build_host_header
      "#{format_host(@uri.host)}:#{@uri.port}"
    end

    def format_origin_host(host)
      return "localhost" if loopback_host?(host)
      format_host(host)
    end

    def format_host(host)
      return host unless host&.include?(":")
      host.start_with?("[") ? host : "[#{host}]"
    end

    def loopback_host?(host)
      return false if host.nil?
      return true if host == "localhost"
      IPAddr.new(host).loopback?
    rescue IPAddr::InvalidAddressError
      false
    end

    def close_socket
      return unless @socket

      begin
        write_frame(@socket, [1000].pack("n"), 0x8)
      rescue IOError, SystemCallError
        # ignore errors while closing
      ensure
        begin
          @socket.close unless @socket.closed?
        rescue IOError, SystemCallError
          nil
        end
        @socket = nil
        @fragments = nil
      end
    end

    def build_path(uri)
      path = uri.path
      path = "/" if path.nil? || path.empty?
      query = uri.query
      path += "?#{query}" if query
      path
    end
  end
end


================================================
FILE: lib/eth/client.rb
================================================
# Copyright (c) 2016-2025 The Ruby-Eth Contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Provides the {Eth} module.
module Eth

  # Provides the {Eth::Client} super-class to connect to Ethereum
  # network's RPC-API endpoints (IPC, HTTP/S, or WS/S).
  class Client

    # The client's RPC-request ID starting at 0.
    attr_reader :id

    # The connected network's chain ID.
    attr_reader :chain_id

    # The connected network's client default account.
    attr_accessor :default_account

    # The default transaction max priority fee per gas in Wei, defaults to {Tx::DEFAULT_PRIORITY_FEE}.
    attr_accessor :max_priority_fee_per_gas

    # The default transaction max fee per gas in Wei, defaults to {Tx::DEFAULT_GAS_PRICE}.
    attr_accessor :max_fee_per_gas

    # The block number used for archive calls.
    attr_accessor :block_number

    # A custom error type if a contract interaction fails.
    class ContractExecutionError < StandardError; end

    # Raised when an RPC call returns an error. Carries the error code and the optional
    # hex-encoded error data to support custom error decoding.
    class RpcError < IOError
      attr_reader :data
      attr_reader :code

      # Constructor for the {RpcError} class.
      #
      # @param message [String] the error message returned by the RPC.
      # @param data [String] optional hex encoded error data.
      # @param code [String] optional error code returned by the RPC.
      def initialize(message, data = nil, code = nil)
        super(message)
        @data = data
        @code = code
      end
    end

    # Creates a new RPC-Client, either by providing an HTTP/S host, WS/S host,
    # or an IPC path. Supports basic authentication with username and password.
    #
    # **Note**, this sets the following gas defaults: {Tx::DEFAULT_PRIORITY_FEE}
    # and {Tx::DEFAULT_GAS_PRICE. Use {#max_priority_fee_per_gas} and
    # {#max_fee_per_gas} to set custom values prior to submitting transactions.
    #
    # @param host [String] either an HTTP/S host, WS/S host, or an IPC path.
    # @return [Eth::Client::Ipc] an IPC client.
    # @return [Eth::Client::Http] an HTTP client.
    # @return [Eth::Client::Ws] a WebSocket client.
    # @raise [ArgumentError] in case it cannot determine the client type.
    def self.create(host)
      return Client::Ipc.new host if host.end_with? ".ipc"
      return Client::Http.new host if host.start_with? "http"
      return Client::Ws.new host if host.start_with? "ws"
      raise ArgumentError, "Unable to detect client type!"
    end

    # Constructor for the {Eth::Client} super-class. Should not be used;
    # use {Client.create} intead.
    def initialize(_)
      @id = 0
      @max_priority_fee_per_gas = Tx::DEFAULT_PRIORITY_FEE
      @max_fee_per_gas = Tx::DEFAULT_GAS_PRICE
    end

    # Gets the default account (first account) of the connected client.
    #
    # **Note**, that many remote providers (e.g., Infura) do not provide
    # any accounts.
    #
    # @return [Eth::Address] the default account address.
    def default_account
      raise ArgumentError, "The default account is not available on remote connections!" unless local? || @default_account
      @default_account ||= Address.new eth_accounts["result"].first
    end

    # Gets the chain ID of the connected network.
    #
    # @return [Integer] the chain ID.
    def chain_id
      @chain_id ||= eth_chain_id["result"].to_i 16
    end

    # Gets the balance for an address.
    #
    # @param address [Eth::Address] the address to get the balance for.
    # @return [Integer] the balance in Wei.
    def get_balance(address)
      eth_get_balance(address)["result"].to_i 16
    end

    # Gets the next nonce for an address used to draft new transactions.
    #
    # @param address [Eth::Address] the address to get the nonce for.
    # @return [Integer] the next nonce to be used.
    def get_nonce(address)
      eth_get_transaction_count(address, "pending")["result"].to_i 16
    end

    # Resolves an ENS name to an Ethereum address on the connected chain.
    #
    # @param ens_name [String] The ENS name, e.g., `fancy.eth`.
    # @param registry [String] the address for the ENS registry.
    # @param coin_type [Integer] the coin type as per EIP-2304.
    # @return [Eth::Address] the Ethereum address resolved from the ENS record.
    def resolve_ens(ens_name, registry = Ens::DEFAULT_ADDRESS, coin_type = Ens::CoinType::ETHEREUM)
      ens = Ens::Resolver.new(self, registry)
      ens.resolve(ens_name, coin_type)
    end

    # Simply transfer Ether to an account and waits for it to be mined.
    # Uses `eth_accounts` and external signer if no sender key is
    # provided.
    #
    # See {#transfer} for params and overloads.
    #
    # @return [String] the transaction hash once it is mined.
    def transfer_and_wait(destination, amount, **kwargs)
      wait_for_tx(transfer(destination, amount, **kwargs))
    end

    # Simply transfer Ether to an account without any call data or
    # access lists attached. Uses `eth_accounts` and external signer
    # if no sender key is provided.
    #
    # **Note**, that many remote providers (e.g., Infura) do not provide
    # any accounts. Provide a `sender_key:` if you experience issues.
    #
    # @overload transfer(destination, amount)
    #   @param destination [Eth::Address] the destination address.
    #   @param amount [Integer] the transfer amount in Wei.
    # @overload transfer(destination, amount, **kwargs)
    #   @param destination [Eth::Address] the destination address.
    #   @param amount [Integer] the transfer amount in Wei.
    #   @param **sender_key [Eth::Key] the sender private key.
    #   @param **legacy [Boolean] enables legacy transactions (pre-EIP-1559).
    #   @param **nonce [Integer] optional specific nonce for transaction.
    # @return [String] the local transaction hash.
    def transfer(destination, amount, **kwargs)
      params = {
        value: amount,
        to: destination,
        gas_limit: Tx::DEFAULT_GAS_LIMIT,
        chain_id: chain_id,
      }
      send_transaction(params, kwargs[:legacy], kwargs[:sender_key], kwargs[:nonce])
    end

    # Transfers a token that implements the ERC20 `transfer()` interface.
    #
    # See {#transfer_erc20} for params and overloads.
    #
    # @return [Object] returns the result of the transaction.
    def transfer_erc20_and_wait(erc20_contract, destination, amount, **kwargs)
      transact_and_wait(erc20_contract, "transfer", destination, amount, **kwargs)
    end

    # Transfers a token that implements the ERC20 `transfer()` interface.
    #
    # **Note**, that many remote providers (e.g., Infura) do not provide
    # any accounts. Provide a `sender_key:` if you experience issues.
    #
    # @overload transfer_erc20(erc20_contract, destination, amount)
    #   @param erc20_contract [Eth::Contract] the ERC20 contract to write to.
    #   @param destination [Eth::Address] the destination address.
    #   @param amount [Integer] the transfer amount (mind the `decimals()`).
    # @overload transfer_erc20(erc20_contract, destination, amount, **kwargs)
    #   @param erc20_contract [Eth::Contract] the ERC20 contract to write to.
    #   @param destination [Eth::Address] the destination address.
    #   @param amount [Integer] the transfer amount (mind the `decimals()`).
    #   @param **sender_key [Eth::Key] the sender private key.
    #   @param **legacy [Boolean] enables legacy transactions (pre-EIP-1559).
    #   @param **gas_limit [Integer] optional gas limit override for the transfer.
    #   @param **nonce [Integer] optional specific nonce for transaction.
    #   @param **tx_value [Integer] optional transaction value field filling.
    # @return [Object] returns the result of the transaction.
    def transfer_erc20(erc20_contract, destination, amount, **kwargs)
      destination = destination.to_s if destination.instance_of? Eth::Address
      transact(erc20_contract, "transfer", destination, amount, **kwargs)
    end

    # Deploys a contract and waits for it to be mined. Uses
    # `eth_accounts` or external signer if no sender key is provided.
    #
    # See {#deploy} for params and overloads.
    #
    # @return [String] the contract address once it's mined.
    def deploy_and_wait(contract, *args, **kwargs)
      hash = wait_for_tx(deploy(contract, *args, **kwargs))
      addr = eth_get_transaction_receipt(hash)["result"]["contractAddress"]
      contract.address = Address.new(addr).to_s
    end

    # Deploys a contract. Uses `eth_accounts` or external signer
    # if no sender key is provided.
    #
    # **Note**, that many remote providers (e.g., Infura) do not provide
    # any accounts. Provide a `sender_key:` if you experience issues.
    #
    # @overload deploy(contract)
    #   @param contract [Eth::Contract] contracts to deploy.
    # @overload deploy(contract, *args)
    #   @param contract [Eth::Contract] the contracts to deploy.
    #   @param *args (optional) variable constructor parameter list.
    # @overload deploy(contract, *args, **kwargs)
    #   @param contract [Eth::Contract] the contracts to deploy.
    #   @param *args (optional) variable constructor parameter list.
    #   @param **sender_key [Eth::Key] the sender private key.
    #   @param **legacy [Boolean] enables legacy transactions (pre-EIP-1559).
    #   @param **gas_limit [Integer] optional gas limit override for deploying the contract.
    #   @param **nonce [Integer] optional specific nonce for transaction.
    # @return [String] the transaction hash.
    # @raise [ArgumentError] in case the contract does not have any source.
    def deploy(contract, *args, **kwargs)
      raise ArgumentError, "Cannot deploy contract without source or binary!" if contract.bin.nil?
      raise ArgumentError, "Missing contract constructor params!" if contract.constructor_inputs.length != args.length
      data = contract.bin
      unless args.empty?
        data += encode_constructor_params(contract, args)
      end
      gas_limit = if kwargs[:gas_limit]
          kwargs[:gas_limit]
        else
          Tx.estimate_intrinsic_gas(data) + Tx::CREATE_GAS
        end
      params = {
        value: 0,
        gas_limit: gas_limit,
        chain_id: chain_id,
        data: data,
      }
      send_transaction(params, kwargs[:legacy], kwargs[:sender_key], kwargs[:nonce])
    end

    # Calls a contract function without executing it
    # (non-transactional contract read).
    #
    # @overload call(contract, function)
    #   @param contract [Eth::Contract] the subject contract to call.
    #   @param function [String] method name to be called.
    # @overload call(contract, function, *args)
    #   @param contract [Eth::Contract] the subject contract to call.
    #   @param function [String] method name to be called.
    #   @param *args optional function arguments.
    # @overload call(contract, function, *args, **kwargs)
    #   @param contract [Eth::Contract] the subject contract to call.
    #   @param function [String] method name to be called.
    #   @param *args optional function arguments.
    #   @param **sender_key [Eth::Key] the sender private key.
    #   @param **legacy [Boolean] enables legacy transactions (pre-EIP-1559).
    # @return [Object] returns the result of the call.
    # @see https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call
    def call(contract, function, *args, **kwargs)
      function = contract.function(function, args: args.size)
      output = function.decode_call_result(
        eth_call(
          {
            data: function.encode_call(*args),
            to: kwargs[:address] || contract.address,
            from: kwargs[:from],
            gas: kwargs[:gas],
            gasPrice: kwargs[:gas_price],
            value: kwargs[:value],
          }.compact
        )["result"]
      )
      if output&.length == 1
        output[0]
      else
        output
      end
    rescue RpcError => e
      raise ContractExecutionError, contract.decode_error(e)
    end

    # Executes a contract function with a transaction (transactional
    # contract read/write).
    #
    # **Note**, that many remote providers (e.g., Infura) do not provide
    # any accounts. Provide a `sender_key:` if you experience issues.
    #
    # @overload transact(contract, function)
    #   @param contract [Eth::Contract] the subject contract to write to.
    #   @param function [String] method name to be executed.
    # @overload transact(contract, function, *args)
    #   @param contract [Eth::Contract] the subject contract to write to.
    #   @param function [String] method name to be executed.
    #   @param *args optional function arguments.
    # @overload transact(contract, function, *args, **kwargs)
    #   @param contract [Eth::Contract] the subject contract to write to.
    #   @param function_name [String] method name to be executed.
    #   @param *args optional function arguments.
    #   @param **sender_key [Eth::Key] the sender private key.
    #   @param **legacy [Boolean] enables legacy transactions (pre-EIP-1559).
    #   @param **address [Eth::Address] contract address.
    #   @param **gas_limit [Integer] optional gas limit override for transacting with the contract.
    #   @param **nonce [Integer] optional specific nonce for transaction.
    #   @param **tx_value [Integer] optional transaction value field filling.
    # @return [Object] returns the result of the transaction.
    def transact(contract, function, *args, **kwargs)
      gas_limit = if kwargs[:gas_limit]
          kwargs[:gas_limit]
        else
          Tx.estimate_intrinsic_gas(contract.bin)
        end
      params = {
        value: kwargs[:tx_value] || 0,
        gas_limit: gas_limit,
        chain_id: chain_id,
        to: kwargs[:address] || contract.address,
        data: contract.function(function, args: args.size).encode_call(*args),
      }
      send_transaction(params, kwargs[:legacy], kwargs[:sender_key], kwargs[:nonce])
    end

    # Executes a contract function with a transaction and waits for it
    # to be mined (transactional contract read/write).
    #
    # See {#transact} for params and overloads.
    #
    # @raise [Client::ContractExecutionError] if the execution fails.
    # @return [Object, Boolean] returns the result of the transaction (hash and execution status).
    def transact_and_wait(contract, function, *args, **kwargs)
      begin
        hash = wait_for_tx(transact(contract, function, *args, **kwargs))
        return hash, tx_succeeded?(hash)
      rescue RpcError => e
        raise ContractExecutionError, contract.decode_error(e)
      end
    end

    # Provides an interface to call `isValidSignature` as per EIP-1271 on a given
    # smart contract to verify the given hash and signature matching the magic
    # value.
    #
    # @param contract [Eth::Contract] a deployed contract implementing EIP-1271.
    # @param hash [String] the message hash to be checked against the signature.
    # @param signature [String] the signature to be recovered by the contract.
    # @param magic [String] the expected magic value (defaults to `1626ba7e`).
    # @return [Boolean] true if magic matches and signature is valid.
    # @raise [ArgumentError] in case the contract cannot be called yet.
    def is_valid_signature(contract, hash, signature, magic = "1626ba7e")
      raise ArgumentError, "Contract not deployed yet." if contract.address.nil?
      hash = Util.hex_to_bin hash if Util.hex? hash
      signature = Util.hex_to_bin signature if Util.hex? signature
      magic = Util.hex_to_bin magic if Util.hex? magic
      result = call(contract, "isValidSignature", hash, signature)
      result === magic
    end

    # Gives control over resetting the RPC request ID back to zero.
    # Usually not needed.
    #
    # @return [Integer] 0
    def reset_id
      @id = 0
    end

    # Checks whether a transaction is mined or not.
    #
    # @param hash [String] the transaction hash.
    # @return [Boolean] true if included in a block.
    def tx_mined?(hash)
      mined_tx = eth_get_transaction_by_hash hash
      !mined_tx.nil? && !mined_tx["result"].nil? && !mined_tx["result"]["blockNumber"].nil?
    end

    # Checks whether a contract transaction succeeded or not.
    #
    # @param hash [String] the transaction hash.
    # @return [Boolean] true if status is success.
    def tx_succeeded?(hash)
      tx_receipt = eth_get_transaction_receipt(hash)
      !tx_receipt.nil? && !tx_receipt["result"].nil? && tx_receipt["result"]["status"] == "0x1"
    end

    # Waits for an transaction to be mined by the connected chain.
    #
    # @param hash [String] the transaction hash.
    # @return [String] the transaction hash once the transaction is mined.
    # @raise [Timeout::Error] if it's not mined within 5 minutes.
    def wait_for_tx(hash)
      start_time = Time.now
      timeout = 300
      retry_rate = 0.1
      loop do
        raise Timeout::Error if ((Time.now - start_time) > timeout)
        return hash if tx_mined? hash
        sleep retry_rate
      end
    end

    # Metafunction to provide all known RPC commands defined in
    # {Eth::Api} as snake_case methods to the {Eth::Client} classes.
    Api::COMMANDS.each do |cmd|
      method_name = cmd.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
      define_method method_name do |*args|
        send_command cmd, args
      end
    end

    private

    # Allows to determine if we work with a local connectoin
    def local?
      if self.instance_of? Eth::Client::Ipc
        true
      elsif self.host === "127.0.0.1" || self.host === "localhost"
        true
      else
        false
      end
    end

    # Prepares a transaction to be send for the given params.
    def send_transaction(params, legacy, key, nonce)
      if legacy
        params.merge!({ gas_price: max_fee_per_gas })
      else
        params.merge!({
          priority_fee: max_priority_fee_per_gas,
          max_gas_fee: max_fee_per_gas,
        })
      end
      unless key.nil?

        # use the provided key as sender and signer
        params.merge!({
          from: key.address,
          nonce: nonce || get_nonce(key.address),
        })
        tx = Eth::Tx.new(params)
        tx.sign key
        eth_send_raw_transaction(tx.hex)["result"]
      else

        # do not allow accessing accounts on remote connections
        raise ArgumentError, "The default account is not available on remote connections, please provide a :sender_key!" unless local?

        # use the default account as sender and external signer
        params.merge!({
          from: default_account,
          nonce: nonce || get_nonce(default_account),
        })
        eth_send_transaction(params)["result"]
      end
    end

    # Encodes constructor params
    def encode_constructor_params(contract, args)
      types = contract.constructor_inputs.map { |input| input.type }
      Util.bin_to_hex(Eth::Abi.encode(types, args))
    end

    # Prepares parameters and sends the command to the client.
    def send_command(command, args)
      @block_number ||= "latest"
      args << block_number if ["eth_getBalance", "eth_call"].include? command
      payload = {
        jsonrpc: "2.0",
        method: command,
        params: marshal(args),
        id: next_id,
      }
      output = JSON.parse(send_request(payload.to_json))
      if (err = output["error"])
        raise RpcError.new(err["message"], err["data"], err["code"])
      end
      output
    end

    # Increments the request id.
    def next_id
      @id += 1
    end

    # expects Hash object
    def camelize!(params)
      params.transform_keys! do |k|
        k = k.to_s.split(/_/).map(&:capitalize).join
        k[0] = k[0].downcase
        k.to_sym
      end
    end

    # Recursively marshals all request parameters.
    def marshal(params)
      params = params.dup
      if params.is_a? Array
        params.map! { |param| marshal(param) }
      elsif params.is_a? Hash
        params = camelize!(params)
        params.transform_values! { |param| marshal(param) }
      elsif params.is_a? Numeric
        Util.prefix_hex "#{params.to_i.to_s(16)}"
      elsif params.is_a? Address
        params.to_s
      elsif Util.hex? params
        Util.prefix_hex params
      else
        params
      end
    end
  end
end

# Load the client/* libraries
require "eth/client/http"
require "eth/client/ipc"
require "eth/client/ws"


================================================
FILE: lib/eth/constant.rb
================================================
# Copyright (c) 2016-2025 The Ruby-Eth Contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

#  -*- encoding : ascii-8bit -*-

# Provides the {Eth} module.
module Eth

  # Provides commonly used constants, such as zero bytes or zero keys.
  module Constant

    # The empty byte is defined as "".
    BYTE_EMPTY = "".freeze

    # The zero byte is 0x00.
    BYTE_ZERO = "\x00".freeze

    # The byte one is 0x01.
    BYTE_ONE = "\x01".freeze

    # The size of a 32-bit number.
    TT32 = (2 ** 32).freeze

    # The size of a 256-bit number.
    TT256 = (2 ** 256).freeze

    # The maximum possible value of an UInt256.
    UINT_MAX = (2 ** 256 - 1).freeze

    # The minimum possible value of an UInt256.
    UINT_MIN = 0.freeze

    # The maximum possible value of an Int256.
    INT_MAX = (2 ** 255 - 1).freeze

    # The minimum possible value of an Int256.
    INT_MIN = (-2 ** 255).freeze

    # A hash containing only zeros.
    HASH_ZERO = ("\x00" * 32).freeze

    # The RLP short length limit.
    SHORT_LENGTH_LIMIT = 56.freeze

    # The RLP long length limit.
    LONG_LENGTH_LIMIT = (256 ** 8).freeze

    # The RLP primitive type offset.
    PRIMITIVE_PREFIX_OFFSET = 0x80.freeze

    # The RLP array type offset.
    LIST_PREFIX_OFFSET = 0xc0.freeze

    # The binary encoding is ASCII (8-bit).
    BINARY_ENCODING = "ASCII-8BIT".freeze

    # Infinity as constant for convenience.
    INFINITY = (1.0 / 0.0).freeze
  end
end


================================================
FILE: lib/eth/contract/error.rb
================================================
# Copyright (c) 2016-2025 The Ruby-Eth Contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# -*- encoding : ascii-8bit -*-

# Provides the {Eth} module.
module Eth
  # Provide classes for contract custom errors.
  class Contract::Error
    attr_accessor :name, :inputs, :signature, :error_string

    # Constructor of the {Eth::Contract::Error} class.
    #
    # @param data [Hash] contract abi data for the error.
    def initialize(data)
      @name = data["name"]
      @inputs = data.fetch("inputs", []).map do |input|
        Eth::Contract::FunctionInput.new(input)
      end
      @error_string = self.class.calc_signature(@name, @inputs)
      @signature = self.class.encoded_error_signature(@error_string)
    end

    # Creates error strings.
    #
    # @param name [String] error name.
    # @param inputs [Array<Eth::Contract::FunctionInput>] error input class list.
    # @return [String] error string.
    def self.calc_signature(name, inputs)
      "#{name}(#{inputs.map { |x| x.parsed_type.to_s }.join(",")})"
    end

    # Encodes an error signature.
    #
    # @param signature [String] error signature.
    # @return [String] encoded error signature string.
    def self.encoded_error_signature(signature)
      Util.prefix_hex(Util.bin_to_hex(Util.keccak256(signature)[0..3]))
    end

    # Decodes a revert error payload.
    #
    # @param data [String] the hex-encoded revert data including selector.
    # @return [Array] decoded error arguments.
    def decode(data)
      types = inputs.map(&:type)
      payload = "0x" + data[10..]
      Eth::Abi.decode(types, payload)
    end
  end
end


================================================
FILE: lib/eth/contract/event.rb
================================================
# Copyright (c) 2016-2025 The Ruby-Eth Contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express o
Download .txt
gitextract_urvyeq_7/

├── .github/
│   ├── dependabot.yml
│   └── workflows/
│       ├── codeql.yml
│       ├── docs.yml
│       └── spec.yml
├── .gitignore
├── .gitmodules
├── .yardopts
├── AUTHORS.txt
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Gemfile
├── LICENSE.txt
├── README.md
├── Rakefile
├── SECURITY.md
├── abi/
│   ├── ens_registry.json
│   └── ens_resolver.json
├── bin/
│   ├── console
│   └── setup
├── codecov.yml
├── eth.gemspec
├── lib/
│   ├── eth/
│   │   ├── abi/
│   │   │   ├── decoder.rb
│   │   │   ├── encoder.rb
│   │   │   ├── event.rb
│   │   │   ├── function.rb
│   │   │   ├── packed/
│   │   │   │   └── encoder.rb
│   │   │   └── type.rb
│   │   ├── abi.rb
│   │   ├── address.rb
│   │   ├── api.rb
│   │   ├── bls.rb
│   │   ├── chain.rb
│   │   ├── client/
│   │   │   ├── http.rb
│   │   │   ├── ipc.rb
│   │   │   └── ws.rb
│   │   ├── client.rb
│   │   ├── constant.rb
│   │   ├── contract/
│   │   │   ├── error.rb
│   │   │   ├── event.rb
│   │   │   ├── function.rb
│   │   │   ├── function_input.rb
│   │   │   ├── function_output.rb
│   │   │   └── initializer.rb
│   │   ├── contract.rb
│   │   ├── eip712.rb
│   │   ├── ens/
│   │   │   ├── coin_type.rb
│   │   │   └── resolver.rb
│   │   ├── ens.rb
│   │   ├── key/
│   │   │   ├── decrypter.rb
│   │   │   └── encrypter.rb
│   │   ├── key.rb
│   │   ├── rlp/
│   │   │   ├── decoder.rb
│   │   │   ├── encoder.rb
│   │   │   ├── sedes/
│   │   │   │   ├── big_endian_int.rb
│   │   │   │   ├── binary.rb
│   │   │   │   └── list.rb
│   │   │   └── sedes.rb
│   │   ├── rlp.rb
│   │   ├── signature.rb
│   │   ├── solidity.rb
│   │   ├── tx/
│   │   │   ├── eip1559.rb
│   │   │   ├── eip2930.rb
│   │   │   ├── eip4844.rb
│   │   │   ├── eip7702.rb
│   │   │   └── legacy.rb
│   │   ├── tx.rb
│   │   ├── unit.rb
│   │   ├── util.rb
│   │   └── version.rb
│   └── eth.rb
└── spec/
    ├── eth/
    │   ├── abi/
    │   │   ├── decoder_spec.rb
    │   │   ├── encoder_spec.rb
    │   │   ├── event_spec.rb
    │   │   ├── function_spec.rb
    │   │   ├── packed/
    │   │   │   └── encoder_spec.rb
    │   │   └── type_spec.rb
    │   ├── abi_spec.rb
    │   ├── address_spec.rb
    │   ├── bls_spec.rb
    │   ├── chain_spec.rb
    │   ├── client/
    │   │   └── ws_spec.rb
    │   ├── client_spec.rb
    │   ├── constant_spec.rb
    │   ├── contract/
    │   │   ├── error_spec.rb
    │   │   ├── event_spec.rb
    │   │   ├── function_input_spec.rb
    │   │   ├── function_output_spec.rb
    │   │   ├── function_spec.rb
    │   │   └── initializer_spec.rb
    │   ├── contract_spec.rb
    │   ├── eip712_spec.rb
    │   ├── ens/
    │   │   ├── coin_type_spec.rb
    │   │   └── resolver_spec.rb
    │   ├── ens_spec.rb
    │   ├── key/
    │   │   ├── decrypter_spec.rb
    │   │   └── encrypter_spec.rb
    │   ├── key_spec.rb
    │   ├── rlp/
    │   │   ├── sedes/
    │   │   │   ├── big_endian_int_spec.rb
    │   │   │   ├── binary_spec.rb
    │   │   │   └── list_spec.rb
    │   │   └── sedes_spec.rb
    │   ├── rlp_spec.rb
    │   ├── signature_spec.rb
    │   ├── solidity_spec.rb
    │   ├── tx/
    │   │   ├── eip1559_spec.rb
    │   │   ├── eip2930_spec.rb
    │   │   ├── eip4844_spec.rb
    │   │   ├── eip7702_spec.rb
    │   │   └── legacy_spec.rb
    │   ├── tx_spec.rb
    │   ├── unit_spec.rb
    │   └── util_spec.rb
    ├── eth_spec.rb
    ├── fixtures/
    │   ├── abi/
    │   │   ├── ENSRegistryWithFallback.json
    │   │   ├── ERC1155.json
    │   │   ├── ERC20.json
    │   │   ├── ERC721.json
    │   │   ├── Tuple.json
    │   │   ├── Tuple2.json
    │   │   └── ethers.json
    │   ├── contracts/
    │   │   ├── address_storage.sol
    │   │   ├── deposit.sol
    │   │   ├── dummy.sol
    │   │   ├── erc20.sol
    │   │   ├── error.sol
    │   │   ├── greeter.sol
    │   │   ├── signer.sol
    │   │   ├── simple_registry.sol
    │   │   ├── test_contract.sol
    │   │   ├── tuple.sol
    │   │   └── tuple2.sol
    │   └── keys/
    │       ├── testingtesting.json
    │       ├── testpassword.json
    │       └── testunknownkdf.json
    └── spec_helper.rb
Download .txt
SYMBOL INDEX (550 symbols across 52 files)

FILE: lib/eth.rb
  type Eth (line 16) | module Eth

FILE: lib/eth/abi.rb
  type Eth (line 20) | module Eth
    type Abi (line 24) | module Abi
      class EncodingError (line 28) | class EncodingError < StandardError; end
      class DecodingError (line 31) | class DecodingError < StandardError; end
      class ValueOutOfBounds (line 34) | class ValueOutOfBounds < StandardError; end
      function encode (line 43) | def encode(types, args, packed = false)
      function solidity_packed (line 79) | def solidity_packed(types, args)
      function decode (line 98) | def decode(types, data)

FILE: lib/eth/abi/decoder.rb
  type Eth (line 18) | module Eth
    type Abi (line 21) | module Abi
      type Decoder (line 24) | module Decoder
        function type (line 33) | def type(type, arg)
        function primitive_type (line 132) | def primitive_type(type, data)
        function tuple_dynamic_ranges (line 195) | def tuple_dynamic_ranges(offsets, total_size, head_size)

FILE: lib/eth/abi/encoder.rb
  type Eth (line 19) | module Eth
    type Abi (line 22) | module Abi
      type Encoder (line 25) | module Encoder
        function type (line 34) | def type(type, arg)
        function primitive_type (line 60) | def primitive_type(type, arg)
        function uint (line 88) | def uint(arg, type)
        function int (line 99) | def int(arg, type)
        function bool (line 110) | def bool(arg)
        function ufixed (line 116) | def ufixed(arg, type)
        function fixed (line 125) | def fixed(arg, type)
        function bytes (line 135) | def bytes(arg, type)
        function tuple (line 155) | def tuple(arg, type)
        function coerce_number (line 190) | def coerce_number(arg)
        function encode_array (line 203) | def encode_array(type, values)
        function encode_dynamic_array (line 225) | def encode_dynamic_array(nested_sub, values)
        function encode_static_array (line 236) | def encode_static_array(nested_sub, values)
        function encode_array_elements (line 246) | def encode_array_elements(nested_sub, values)
        function hash (line 264) | def hash(arg, type)
        function address (line 285) | def address(arg)
        function handle_hex_string (line 313) | def handle_hex_string(arg, type)

FILE: lib/eth/abi/event.rb
  type Eth (line 18) | module Eth
    type Abi (line 21) | module Abi
      type Event (line 24) | module Event
        function compute_topic (line 31) | def compute_topic(interface)
        function signature (line 40) | def signature(interface)
        function type (line 51) | def type(input)
        class LogDescription (line 62) | class LogDescription
          method initialize (line 79) | def initialize(event_interface, log)
          method name (line 92) | def name
          method signature (line 97) | def signature
        function decode_logs (line 107) | def decode_logs(interfaces, logs)
        function decode_log (line 130) | def decode_log(inputs, data, topics, anonymous = false)

FILE: lib/eth/abi/function.rb
  type Eth (line 18) | module Eth
    type Abi (line 21) | module Abi
      type Function (line 24) | module Function
        function signature (line 31) | def signature(interface)
        function selector (line 42) | def selector(interface)
        function type (line 51) | def type(input)
        class CallDescription (line 62) | class CallDescription
          method initialize (line 81) | def initialize(function_interface, selector, args, kwargs)
          method name (line 89) | def name
          method signature (line 94) | def signature
        function decode (line 104) | def decode(interfaces, data)

FILE: lib/eth/abi/packed/encoder.rb
  type Eth (line 18) | module Eth
    type Abi (line 21) | module Abi
      type Packed (line 24) | module Packed
        type Encoder (line 27) | module Encoder
          function type (line 38) | def type(type, arg)
          function uint (line 74) | def uint(value, byte_size)
          function int (line 82) | def int(value, byte_size)
          function bool (line 91) | def bool(value)
          function ufixed (line 97) | def ufixed(value, byte_size, decimals)
          function fixed (line 105) | def fixed(value, byte_size, decimals)
          function bytes (line 113) | def bytes(value, length)
          function string (line 121) | def string(value)
          function tuple (line 127) | def tuple(types, values)
          function hash (line 132) | def hash(value, byte_size)
          function address (line 139) | def address(value)
          function array (line 166) | def array(type, values)
          function fixed_array (line 171) | def fixed_array(type, values, size)
          function handle_hex_string (line 178) | def handle_hex_string(val, len)

FILE: lib/eth/abi/type.rb
  type Eth (line 18) | module Eth
    type Abi (line 21) | module Abi
      class Type (line 24) | class Type
        class ParseError (line 27) | class ParseError < StandardError; end
        method initialize (line 53) | def initialize(base_type, sub_type, dimensions, components = nil, ...
        method parse (line 73) | def parse(type, components = nil, component_name = nil)
        method size_type (line 121) | def self.size_type
        method == (line 129) | def ==(another_type)
        method size (line 138) | def size
        method dynamic? (line 155) | def dynamic?
        method nested_sub (line 162) | def nested_sub
        method to_s (line 169) | def to_s
        method validate_base_type (line 186) | def validate_base_type(base_type, sub_type)
        method extract_tuple (line 237) | def extract_tuple(type)
        method split_tuple_types (line 256) | def split_tuple_types(str)

FILE: lib/eth/address.rb
  type Eth (line 16) | module Eth
    class Address (line 19) | class Address
      class CheckSumError (line 25) | class CheckSumError < StandardError; end
      method initialize (line 34) | def initialize(address)
      method valid? (line 47) | def valid?
      method zero? (line 60) | def zero?
      method checksummed (line 67) | def checksummed
      method checksum_matches? (line 82) | def checksum_matches?
      method not_checksummed? (line 87) | def not_checksummed?
      method all_uppercase? (line 92) | def all_uppercase?
      method all_lowercase? (line 97) | def all_lowercase?
      method matches_any_format? (line 102) | def matches_any_format?
      method checksum (line 107) | def checksum
      method unprefixed (line 112) | def unprefixed

FILE: lib/eth/api.rb
  type Eth (line 16) | module Eth
    type Api (line 19) | module Api

FILE: lib/eth/bls.rb
  type Eth (line 5) | module Eth
    type Bls (line 7) | module Bls
      function decode_public_key (line 13) | def decode_public_key(hex)
      function encode_public_key (line 20) | def encode_public_key(point)
      function decode_signature (line 27) | def decode_signature(hex)
      function encode_signature (line 34) | def encode_signature(point)
      function get_public_key (line 41) | def get_public_key(priv_hex)
      function sign (line 50) | def sign(message, priv_hex)
      function verify (line 62) | def verify(message, signature_hex, pubkey_hex)

FILE: lib/eth/chain.rb
  type Eth (line 16) | module Eth
    type Chain (line 20) | module Chain
      class ReplayProtectionError (line 24) | class ReplayProtectionError < StandardError; end
      function ledger? (line 175) | def ledger?(v)
      function legacy? (line 184) | def legacy?(v)
      function to_recovery_id (line 195) | def to_recovery_id(v, chain_id = ETHEREUM)
      function to_v (line 220) | def to_v(recovery_id, chain_id = nil)
      function to_chain_id (line 234) | def to_chain_id(v)

FILE: lib/eth/client.rb
  type Eth (line 16) | module Eth
    class Client (line 20) | class Client
      class ContractExecutionError (line 41) | class ContractExecutionError < StandardError; end
      class RpcError (line 45) | class RpcError < IOError
        method initialize (line 54) | def initialize(message, data = nil, code = nil)
      method create (line 73) | def self.create(host)
      method initialize (line 82) | def initialize(_)
      method default_account (line 94) | def default_account
      method chain_id (line 102) | def chain_id
      method get_balance (line 110) | def get_balance(address)
      method get_nonce (line 118) | def get_nonce(address)
      method resolve_ens (line 128) | def resolve_ens(ens_name, registry = Ens::DEFAULT_ADDRESS, coin_type...
      method transfer_and_wait (line 140) | def transfer_and_wait(destination, amount, **kwargs)
      method transfer (line 161) | def transfer(destination, amount, **kwargs)
      method transfer_erc20_and_wait (line 176) | def transfer_erc20_and_wait(erc20_contract, destination, amount, **k...
      method transfer_erc20 (line 199) | def transfer_erc20(erc20_contract, destination, amount, **kwargs)
      method deploy_and_wait (line 210) | def deploy_and_wait(contract, *args, **kwargs)
      method deploy (line 236) | def deploy(contract, *args, **kwargs)
      method call (line 275) | def call(contract, function, *args, **kwargs)
      method transact (line 322) | def transact(contract, function, *args, **kwargs)
      method transact_and_wait (line 345) | def transact_and_wait(contract, function, *args, **kwargs)
      method is_valid_signature (line 364) | def is_valid_signature(contract, hash, signature, magic = "1626ba7e")
      method reset_id (line 377) | def reset_id
      method tx_mined? (line 385) | def tx_mined?(hash)
      method tx_succeeded? (line 394) | def tx_succeeded?(hash)
      method wait_for_tx (line 404) | def wait_for_tx(hash)
      method local? (line 427) | def local?
      method send_transaction (line 438) | def send_transaction(params, legacy, key, nonce)
      method encode_constructor_params (line 472) | def encode_constructor_params(contract, args)
      method send_command (line 478) | def send_command(command, args)
      method next_id (line 495) | def next_id
      method camelize! (line 500) | def camelize!(params)
      method marshal (line 509) | def marshal(params)

FILE: lib/eth/client/http.rb
  type Eth (line 19) | module Eth
    class Client::Http (line 22) | class Client::Http < Client
      method initialize (line 43) | def initialize(host)
      method send_request (line 68) | def send_request(payload)

FILE: lib/eth/client/ipc.rb
  type Eth (line 18) | module Eth
    class Client::Ipc (line 21) | class Client::Ipc < Client
      method initialize (line 30) | def initialize(path)
      method send_request (line 39) | def send_request(payload)

FILE: lib/eth/client/ws.rb
  type Eth (line 25) | module Eth
    class Client::Ws (line 28) | class Client::Ws < Client
      method initialize (line 46) | def initialize(host)
      method send_request (line 63) | def send_request(payload)
      method close (line 82) | def close
      method ensure_socket (line 88) | def ensure_socket
      method open_socket (line 115) | def open_socket
      method perform_handshake (line 132) | def perform_handshake(socket)
      method build_handshake_request (line 140) | def build_handshake_request(key)
      method read_handshake_response (line 152) | def read_handshake_response(socket)
      method verify_handshake! (line 164) | def verify_handshake!(response, key)
      method write_frame (line 176) | def write_frame(socket, payload, opcode = 0x1)
      method read_message (line 196) | def read_message(socket)
      method read_frame (line 203) | def read_frame(socket)
      method read_bytes (line 251) | def read_bytes(socket, length)
      method apply_mask (line 261) | def apply_mask(payload, mask_key)
      method build_origin_header (line 266) | def build_origin_header
      method build_host_header (line 275) | def build_host_header
      method format_origin_host (line 279) | def format_origin_host(host)
      method format_host (line 284) | def format_host(host)
      method loopback_host? (line 289) | def loopback_host?(host)
      method close_socket (line 297) | def close_socket
      method build_path (line 315) | def build_path(uri)

FILE: lib/eth/constant.rb
  type Eth (line 18) | module Eth
    type Constant (line 21) | module Constant

FILE: lib/eth/contract.rb
  type Eth (line 20) | module Eth
    class Contract (line 23) | class Contract
      method initialize (line 38) | def initialize(name, bin, abi)
      method from_file (line 56) | def self.from_file(file:, contract_index: 0)
      method from_abi (line 71) | def self.from_abi(abi:, address:, name:)
      method from_bin (line 88) | def self.from_bin(bin:, abi:, name:)
      method address= (line 98) | def address=(addr)
      method function (line 115) | def function(name, args: nil)
      method error (line 127) | def error(name, args: nil)
      method decode_error (line 137) | def decode_error(rpc_error)
      method build (line 156) | def build
      method parse_abi (line 183) | def parse_abi(abi)

FILE: lib/eth/contract/error.rb
  type Eth (line 18) | module Eth
    class Contract::Error (line 20) | class Contract::Error
      method initialize (line 26) | def initialize(data)
      method calc_signature (line 40) | def self.calc_signature(name, inputs)
      method encoded_error_signature (line 48) | def self.encoded_error_signature(signature)
      method decode (line 56) | def decode(data)

FILE: lib/eth/contract/event.rb
  type Eth (line 18) | module Eth
    class Contract::Event (line 20) | class Contract::Event
      method initialize (line 24) | def initialize(data)
      method name (line 31) | def name
      method input_types (line 38) | def input_types
      method inputs (line 45) | def inputs
      method event_string (line 52) | def event_string
      method signature (line 59) | def signature
      method address (line 66) | def address
      method set_address (line 73) | def set_address(address)
      method decode_params (line 82) | def decode_params(topics, data = "0x")
      method type_name (line 100) | def type_name(x)

FILE: lib/eth/contract/function.rb
  type Eth (line 18) | module Eth
    class Contract::Function (line 21) | class Contract::Function
      method initialize (line 27) | def initialize(data)
      method calc_signature (line 45) | def self.calc_signature(name, inputs)
      method encoded_function_signature (line 53) | def self.encoded_function_signature(signature)
      method encode_call (line 61) | def encode_call(*args)
      method decode_call_result (line 71) | def decode_call_result(data)

FILE: lib/eth/contract/function_input.rb
  type Eth (line 18) | module Eth
    class Contract::FunctionInput (line 21) | class Contract::FunctionInput
      method initialize (line 27) | def initialize(data)
      method type (line 34) | def type
      method parsed_type (line 39) | def parsed_type

FILE: lib/eth/contract/function_output.rb
  type Eth (line 18) | module Eth
    class Contract::FunctionOutput (line 21) | class Contract::FunctionOutput
      method initialize (line 27) | def initialize(data)
      method type (line 34) | def type
      method parsed_type (line 41) | def parsed_type

FILE: lib/eth/contract/initializer.rb
  type Eth (line 18) | module Eth
    class Contract::Initializer (line 21) | class Contract::Initializer
      method initialize (line 27) | def initialize(file)
      method build_all (line 41) | def build_all

FILE: lib/eth/eip712.rb
  type Eth (line 16) | module Eth
    type Eip712 (line 20) | module Eip712
      class TypedDataError (line 25) | class TypedDataError < StandardError; end
      function type_dependencies (line 34) | def type_dependencies(primary_type, types, result = [])
      function encode_type (line 68) | def encode_type(primary_type, types)
      function hash_type (line 100) | def hash_type(primary_type, types)
      function encode_data (line 111) | def encode_data(primary_type, data, types)
      function encode_value (line 139) | def encode_value(type, value, types)
      function encode_array (line 156) | def encode_array(type, value, types)
      function hash_data (line 180) | def hash_data(primary_type, data, types)
      function enforce_typed_data (line 191) | def enforce_typed_data(data)
      function hash (line 207) | def hash(data)

FILE: lib/eth/ens.rb
  type Eth (line 19) | module Eth
    type Ens (line 22) | module Ens

FILE: lib/eth/ens/coin_type.rb
  type Eth (line 16) | module Eth
    type Ens (line 19) | module Ens
      type CoinType (line 22) | module CoinType

FILE: lib/eth/ens/resolver.rb
  type Eth (line 18) | module Eth
    type Ens (line 22) | module Ens
      class Resolver (line 25) | class Resolver
        method initialize (line 37) | def initialize(client, address = DEFAULT_ADDRESS)
        method owner (line 50) | def owner(ens_name)
        method resolver (line 59) | def resolver(ens_name)
        method resolve (line 72) | def resolve(ens_name, coin_type = Ens::CoinType::ETHEREUM)
        method text (line 88) | def text(ens_name, key = "description")
        method namehash (line 97) | def namehash(ens_name)
        method normalize (line 111) | def normalize(input)

FILE: lib/eth/key.rb
  type Eth (line 22) | module Eth
    class Key (line 25) | class Key
      method initialize (line 43) | def initialize(priv: nil)
      method sign (line 72) | def sign(blob, chain_id = nil)
      method personal_sign (line 94) | def personal_sign(message, chain_id = nil)
      method sign_typed_data (line 109) | def sign_typed_data(typed_data, chain_id = nil)
      method private_hex (line 117) | def private_hex
      method private_bytes (line 125) | def private_bytes
      method public_hex (line 133) | def public_hex
      method public_hex_compressed (line 141) | def public_hex_compressed
      method public_bytes (line 149) | def public_bytes
      method public_bytes_compressed (line 156) | def public_bytes_compressed
      method address (line 163) | def address

FILE: lib/eth/key/decrypter.rb
  type Eth (line 16) | module Eth
    class Key::Decrypter (line 19) | class Key::Decrypter
      class DecrypterError (line 22) | class DecrypterError < StandardError; end
      method perform (line 30) | def self.perform(data, password)
      method initialize (line 40) | def initialize(data, password)
      method perform (line 49) | def perform
      method derive_key (line 62) | def derive_key(password)
      method check_macs (line 73) | def check_macs
      method decrypted_data (line 82) | def decrypted_data
      method crypto_data (line 86) | def crypto_data
      method ciphertext (line 90) | def ciphertext
      method cipher_name (line 94) | def cipher_name
      method cipher (line 98) | def cipher
      method iv (line 106) | def iv
      method salt (line 110) | def salt
      method iterations (line 114) | def iterations
      method kdf (line 118) | def kdf
      method key_length (line 122) | def key_length
      method n (line 126) | def n
      method r (line 130) | def r
      method p (line 134) | def p
      method digest (line 138) | def digest
      method digest_name (line 142) | def digest_name

FILE: lib/eth/key/encrypter.rb
  type Eth (line 16) | module Eth
    class Key::Encrypter (line 19) | class Key::Encrypter
      class EncrypterError (line 22) | class EncrypterError < StandardError; end
      method perform (line 37) | def self.perform(key, password, options = {})
      method initialize (line 54) | def initialize(key, options = {})
      method perform (line 70) | def perform(password)
      method data (line 80) | def data
      method cipher (line 119) | def cipher
      method digest (line 127) | def digest
      method derive_key (line 131) | def derive_key(password)
      method encrypt (line 139) | def encrypt
      method mac (line 143) | def mac
      method kdf (line 147) | def kdf
      method cipher_name (line 151) | def cipher_name
      method digest_name (line 155) | def digest_name
      method prf (line 159) | def prf
      method key_length (line 163) | def key_length
      method salt_length (line 167) | def salt_length
      method iv_length (line 171) | def iv_length
      method id (line 175) | def id
      method iterations (line 179) | def iterations
      method salt (line 183) | def salt
      method iv (line 191) | def iv
      method parallelization (line 199) | def parallelization
      method block_size (line 203) | def block_size

FILE: lib/eth/rlp.rb
  type Eth (line 23) | module Eth
    type Rlp (line 26) | module Rlp
      class RlpException (line 30) | class RlpException < StandardError; end
      class EncodingError (line 33) | class EncodingError < RlpException; end
      class DecodingError (line 36) | class DecodingError < RlpException; end
      class SerializationError (line 39) | class SerializationError < RlpException; end
      class DeserializationError (line 42) | class DeserializationError < RlpException; end
      class Data (line 45) | class Data < String; end
      function encode (line 51) | def encode(obj)
      function decode (line 59) | def decode(rlp)

FILE: lib/eth/rlp/decoder.rb
  type Eth (line 18) | module Eth
    type Rlp (line 21) | module Rlp
      type Decoder (line 24) | module Decoder
        function perform (line 33) | def perform(rlp)
        function consume_item (line 48) | def consume_item(rlp, start)
        function consume_length_prefix (line 54) | def consume_length_prefix(rlp, start)
        function enforce_no_zero_bytes (line 89) | def enforce_no_zero_bytes(rlp, start)
        function consume_payload (line 94) | def consume_payload(rlp, start, type, length)

FILE: lib/eth/rlp/encoder.rb
  type Eth (line 18) | module Eth
    type Rlp (line 21) | module Rlp
      type Encoder (line 24) | module Encoder
        function perform (line 34) | def perform(obj)
        function encode_raw (line 42) | def encode_raw(item)
        function encode_primitive (line 50) | def encode_primitive(item)
        function encode_list (line 58) | def encode_list(list)
        function length_prefix (line 65) | def length_prefix(length, offset)

FILE: lib/eth/rlp/sedes.rb
  type Eth (line 22) | module Eth
    type Rlp (line 25) | module Rlp
      type Sedes (line 28) | module Sedes
        function infer (line 41) | def infer(obj)
        function sedes? (line 53) | def sedes?(obj)
        function big_endian_int (line 61) | def big_endian_int
        function binary (line 68) | def binary

FILE: lib/eth/rlp/sedes/big_endian_int.rb
  type Eth (line 18) | module Eth
    type Rlp (line 21) | module Rlp
      type Sedes (line 24) | module Sedes
        class BigEndianInt (line 27) | class BigEndianInt
          method initialize (line 32) | def initialize(size = nil)
          method serialize (line 43) | def serialize(obj)
          method deserialize (line 57) | def deserialize(serial)

FILE: lib/eth/rlp/sedes/binary.rb
  type Eth (line 18) | module Eth
    type Rlp (line 21) | module Rlp
      type Sedes (line 24) | module Sedes
        class Binary (line 27) | class Binary
          method fixed_length (line 37) | def fixed_length(l, allow_empty: false)
          method valid_type? (line 45) | def valid_type?(obj)
          method initialize (line 55) | def initialize(min_length: 0, max_length: Constant::INFINITY, al...
          method serialize (line 67) | def serialize(obj)
          method deserialize (line 80) | def deserialize(serial)
          method valid_length? (line 91) | def valid_length?(length)

FILE: lib/eth/rlp/sedes/list.rb
  type Eth (line 18) | module Eth
    type Rlp (line 21) | module Rlp
      type Sedes (line 24) | module Sedes
        class List (line 27) | class List < Array
          method initialize (line 33) | def initialize(elements: [], strict: true)
          method serialize (line 53) | def serialize(obj)
          method deserialize (line 69) | def deserialize(serial)

FILE: lib/eth/signature.rb
  type Eth (line 18) | module Eth
    type Signature (line 21) | module Signature
      class SignatureError (line 25) | class SignatureError < StandardError; end
      function prefix_message (line 40) | def prefix_message(message)
      function dissect (line 50) | def dissect(signature)
      function recover (line 69) | def recover(blob, signature, chain_id = Chain::ETHEREUM)
      function personal_recover (line 92) | def personal_recover(message, signature, chain_id = Chain::ETHEREUM)
      function recover_typed_data (line 106) | def recover_typed_data(typed_data, signature, chain_id = Chain::ETHE...
      function verify (line 119) | def verify(blob, signature, public_key, chain_id = Chain::ETHEREUM)

FILE: lib/eth/solidity.rb
  type Eth (line 18) | module Eth
    class Solidity (line 21) | class Solidity
      class CompilerError (line 24) | class CompilerError < StandardError; end
      method initialize (line 33) | def initialize(path = nil)
      method compile (line 45) | def compile(contract)
      method get_compiler_path (line 68) | def get_compiler_path(name = "solc")

FILE: lib/eth/tx.rb
  type Eth (line 26) | module Eth
    type Tx (line 29) | module Tx
      class TransactionTypeError (line 33) | class TransactionTypeError < TypeError; end
      class DecoderError (line 36) | class DecoderError < StandardError; end
      class ParameterError (line 39) | class ParameterError < TypeError; end
      function new (line 103) | def new(params, chain_id = Chain::ETHEREUM)
      function decode (line 139) | def decode(hex)
      function unsigned_copy (line 176) | def unsigned_copy(tx)
      function estimate_intrinsic_gas (line 208) | def estimate_intrinsic_gas(data = "", list = [])
      function validate_params (line 250) | def validate_params(fields)
      function validate_eip1559_params (line 275) | def validate_eip1559_params(fields)
      function validate_eip4844_params (line 290) | def validate_eip4844_params(fields)
      function validate_eip7702_params (line 311) | def validate_eip7702_params(fields)
      function validate_legacy_params (line 323) | def validate_legacy_params(fields)
      function sanitize_chain (line 335) | def sanitize_chain(id)
      function sanitize_address (line 346) | def sanitize_address(addr)
      function sanitize_amount (line 360) | def sanitize_amount(val)
      function sanitize_data (line 370) | def sanitize_data(data)
      function sanitize_list (line 384) | def sanitize_list(list)
      function sanitize_hashes (line 406) | def sanitize_hashes(list)
      function signed? (line 419) | def signed?(tx)

FILE: lib/eth/tx/eip1559.rb
  type Eth (line 16) | module Eth
    type Tx (line 19) | module Tx
      class Eip1559 (line 24) | class Eip1559
        method initialize (line 86) | def initialize(params)
        method decode (line 139) | def decode(hex)
        method unsigned_copy (line 206) | def unsigned_copy(tx)
        method sign (line 238) | def sign(key)
        method sign_with (line 266) | def sign_with(signature)
        method encoded (line 290) | def encoded
        method hex (line 317) | def hex
        method hash (line 324) | def hash
        method unsigned_encoded (line 332) | def unsigned_encoded
        method unsigned_hash (line 353) | def unsigned_hash
        method _set_signature (line 360) | def _set_signature(recovery_id, r, s)

FILE: lib/eth/tx/eip2930.rb
  type Eth (line 16) | module Eth
    type Tx (line 19) | module Tx
      class Eip2930 (line 24) | class Eip2930
        method initialize (line 84) | def initialize(params)
        method decode (line 136) | def decode(hex)
        method unsigned_copy (line 201) | def unsigned_copy(tx)
        method sign (line 232) | def sign(key)
        method sign_with (line 260) | def sign_with(signature)
        method encoded (line 284) | def encoded
        method hex (line 310) | def hex
        method hash (line 317) | def hash
        method unsigned_encoded (line 325) | def unsigned_encoded
        method unsigned_hash (line 345) | def unsigned_hash
        method _set_signature (line 352) | def _set_signature(recovery_id, r, s)

FILE: lib/eth/tx/eip4844.rb
  type Eth (line 16) | module Eth
    type Tx (line 19) | module Tx
      class Eip4844 (line 24) | class Eip4844
        method initialize (line 106) | def initialize(params)
        method decode (line 163) | def decode(hex)
        method unsigned_copy (line 234) | def unsigned_copy(tx)
        method sign (line 268) | def sign(key)
        method sign_with (line 296) | def sign_with(signature)
        method encoded (line 320) | def encoded
        method hex (line 349) | def hex
        method hash (line 356) | def hash
        method unsigned_encoded (line 364) | def unsigned_encoded
        method unsigned_hash (line 387) | def unsigned_hash
        method _set_signature (line 394) | def _set_signature(recovery_id, r, s)

FILE: lib/eth/tx/eip7702.rb
  type Eth (line 16) | module Eth
    type Tx (line 19) | module Tx
      class Eip7702 (line 24) | class Eip7702
        class Authorization (line 28) | class Authorization
          method initialize (line 57) | def initialize(fields)
          method sign (line 72) | def sign(key)
          method unsigned_encoded (line 97) | def unsigned_encoded
          method unsigned_hash (line 108) | def unsigned_hash
          method raw (line 115) | def raw
          method == (line 130) | def ==(o)
          method state (line 136) | def state
        method initialize (line 205) | def initialize(params)
        method decode (line 260) | def decode(hex)
        method unsigned_copy (line 330) | def unsigned_copy(tx)
        method sign (line 370) | def sign(key)
        method sign_with (line 398) | def sign_with(signature)
        method encoded (line 422) | def encoded
        method hex (line 453) | def hex
        method hash (line 460) | def hash
        method unsigned_encoded (line 468) | def unsigned_encoded
        method unsigned_hash (line 494) | def unsigned_hash
        method deserialize_authorizations (line 500) | def deserialize_authorizations(authorization_list)
        method _set_signature (line 513) | def _set_signature(recovery_id, r, s)

FILE: lib/eth/tx/legacy.rb
  type Eth (line 16) | module Eth
    type Tx (line 19) | module Tx
      class Legacy (line 23) | class Legacy
        method initialize (line 76) | def initialize(params, chain_id = Chain::ETHEREUM)
        method decode (line 123) | def decode(hex)
        method unsigned_copy (line 175) | def unsigned_copy(tx)
        method sign (line 205) | def sign(key)
        method sign_with (line 232) | def sign_with(signature)
        method encoded (line 254) | def encoded
        method hex (line 274) | def hex
        method hash (line 281) | def hash
        method unsigned_encoded (line 288) | def unsigned_encoded
        method unsigned_hash (line 305) | def unsigned_hash
        method _set_signature (line 312) | def _set_signature(v, r, s)

FILE: lib/eth/unit.rb
  type Eth (line 18) | module Eth
    type Unit (line 21) | module Unit

FILE: lib/eth/util.rb
  type Eth (line 20) | module Eth
    type Util (line 23) | module Util
      function public_key_to_address (line 31) | def public_key_to_address(str)
      function keccak256 (line 42) | def keccak256(str)
      function bin_to_hex (line 51) | def bin_to_hex(bin)
      function hex_to_bin (line 62) | def hex_to_bin(hex)
      function prefix_hex (line 74) | def prefix_hex(hex)
      function remove_hex_prefix (line 82) | def remove_hex_prefix(hex)
      function bin_to_prefixed_hex (line 91) | def bin_to_prefixed_hex(bin)
      function hex? (line 99) | def hex?(str)
      function prefixed? (line 109) | def prefixed?(hex)
      function serialize_int_to_big_endian (line 118) | def serialize_int_to_big_endian(num)
      function int_to_big_endian (line 130) | def int_to_big_endian(num)
      function deserialize_big_endian_to_int (line 144) | def deserialize_big_endian_to_int(str)
      function deserialize_rlp_int (line 153) | def deserialize_rlp_int(str)
      function big_endian_to_int (line 161) | def big_endian_to_int(str)
      function str_to_bytes (line 169) | def str_to_bytes(str)
      function bytes_to_str (line 177) | def bytes_to_str(bin)
      function bytes? (line 185) | def bytes?(str)
      function primitive? (line 193) | def primitive?(item)
      function list? (line 201) | def list?(item)
      function ceil32 (line 209) | def ceil32(num)
      function lpad (line 219) | def lpad(str, sym, len)
      function zpad (line 229) | def zpad(str, len)
      function zpad_hex (line 238) | def zpad_hex(hex, len = 32)
      function zpad_int (line 247) | def zpad_int(num, len = 32)

FILE: lib/eth/version.rb
  type Eth (line 16) | module Eth

FILE: spec/eth/abi_spec.rb
  function assert (line 363) | def assert(data, types, args)

FILE: spec/eth/client/ws_spec.rb
  class DummyWebsocketServer (line 25) | class DummyWebsocketServer
    method initialize (line 30) | def initialize
    method start (line 45) | def start
    method stop (line 50) | def stop
    method serve (line 62) | def serve
    method handle_client (line 73) | def handle_client(socket)
    method perform_handshake (line 101) | def perform_handshake(socket)
    method rpc_response_for (line 125) | def rpc_response_for(message)
    method read_frame (line 156) | def read_frame(socket)
    method send_frame (line 180) | def send_frame(socket, payload, opcode = 0x1)
    method send_close (line 196) | def send_close(socket)
    method success (line 200) | def success(id, result)
    method error (line 208) | def error(id, message)
    method record_transaction (line 216) | def record_transaction(tx)
    method build_tx_hash (line 240) | def build_tx_hash(from, to, nonce, value)
    method normalize_address (line 245) | def normalize_address(address)
    method hex_to_int (line 250) | def hex_to_int(value)
    method to_hex (line 257) | def to_hex(number)

FILE: spec/eth/key/decrypter_spec.rb
  function read_key_fixture (line 4) | def read_key_fixture(path)
Condensed preview — 136 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (8,267K chars).
[
  {
    "path": ".github/dependabot.yml",
    "chars": 308,
    "preview": "---\nupdates:\n  -\n    directory: /\n    labels:\n      - dependencies\n    package-ecosystem: bundler\n    schedule:\n      in"
  },
  {
    "path": ".github/workflows/codeql.yml",
    "chars": 1093,
    "preview": "---\nname: CodeQL\n\non:\n  pull_request:\n    branches:\n      - main\n  push:\n    branches:\n      - main\n\njobs:\n  analyze:\n  "
  },
  {
    "path": ".github/workflows/docs.yml",
    "chars": 465,
    "preview": "---\nname: Docs\n\non:\n  push:\n    branches:\n      - main\n\njobs:\n  docs:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: "
  },
  {
    "path": ".github/workflows/spec.yml",
    "chars": 1825,
    "preview": "---\nname: Spec\n\non:\n  pull_request:\n    branches:\n      - main\n  push:\n    branches:\n      - main\n  schedule:\n    -\n    "
  },
  {
    "path": ".gitignore",
    "chars": 660,
    "preview": "*.DS_Store\n\n*.o\n*.so\n*.gem\n*.log\n*.rbc\n.config\n.rake_tasks~\ncoverage/\nInstalledFiles\npkg/\ntmp/\n\n# RSpec configuration an"
  },
  {
    "path": ".gitmodules",
    "chars": 125,
    "preview": "[submodule \"spec/fixtures/ethereum/tests\"]\n\tpath = spec/fixtures/ethereum/tests\n\turl = https://github.com/ethereum/tests"
  },
  {
    "path": ".yardopts",
    "chars": 61,
    "preview": "--verbose --fail-on-warning --markup markdown --embed-mixins\n"
  },
  {
    "path": "AUTHORS.txt",
    "chars": 1043,
    "preview": "The Ruby-Eth Contributors are:\n* Steve Ellis @se3000\n* Afri Schoedon @q9f\n* John Omar @chainoperator\n* Joshua Peek @josh"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 24847,
    "preview": "# Change Log\nAll notable changes to this project will be documented in this file.\n\n## [0.5.15]\n### Added\n* Implement EIP"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 4956,
    "preview": "\n# Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our\ncommunit"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 1656,
    "preview": "# Contributing to Ruby Ethereum\n\nEveryone is welcome to contribute to the Ruby Ethereum gem. It is\nmore than six years o"
  },
  {
    "path": "Gemfile",
    "chars": 340,
    "preview": "# frozen_string_literal: true\n\nsource \"https://rubygems.org\"\n\ngroup :test, :development do\n  gem \"bundler\", \">= 2.4\"\n  g"
  },
  {
    "path": "LICENSE.txt",
    "chars": 11365,
    "preview": "\n                                 Apache License\n                           Version 2.0, January 2004\n                  "
  },
  {
    "path": "README.md",
    "chars": 5262,
    "preview": "<!--\n# @markup markdown\n# @title Ethereum for Ruby\n# @author Afri Schoedon\n-->\n\n# Ethereum for Ruby\n\n[![GitHub Workflow "
  },
  {
    "path": "Rakefile",
    "chars": 117,
    "preview": "require \"bundler/gem_tasks\"\nrequire \"rspec/core/rake_task\"\n\nRSpec::Core::RakeTask.new(:spec)\n\ntask :default => :spec\n"
  },
  {
    "path": "SECURITY.md",
    "chars": 761,
    "preview": "# Security Policy\n\n## Supported Versions\n\nRuby Ethereum 0.5.x is a complete rewrite of the old `eth` 0.4.x gem.\nIt also "
  },
  {
    "path": "abi/ens_registry.json",
    "chars": 7720,
    "preview": "[\n  {\n    \"inputs\":[\n      {\n        \"internalType\":\"contract ENS\",\n        \"name\":\"_old\",\n        \"type\":\"address\"\n    "
  },
  {
    "path": "abi/ens_resolver.json",
    "chars": 17595,
    "preview": "[\n    {\n      \"inputs\":[\n        {\n          \"internalType\":\"contract ENS\",\n          \"name\":\"_ens\",\n          \"type\":\"a"
  },
  {
    "path": "bin/console",
    "chars": 204,
    "preview": "#!/usr/bin/env ruby\n\n# use the local version of the code instead of a globally installed gem\n$LOAD_PATH.unshift File.exp"
  },
  {
    "path": "bin/setup",
    "chars": 197,
    "preview": "#!/usr/bin/env bash\n\nbundle install\ngit submodule update --init --recursive\nrufo .\nyard doc\nrspec\n\necho \"Tests fail? Run"
  },
  {
    "path": "codecov.yml",
    "chars": 90,
    "preview": "coverage:\n  status:\n    project:\n      default:\n        target: 99%\n        threshold: 1%\n"
  },
  {
    "path": "eth.gemspec",
    "chars": 2194,
    "preview": "# frozen_string_literal: true\n# coding: utf-8\n\nlib = File.expand_path(\"lib\", __dir__).freeze\n$LOAD_PATH.unshift lib unle"
  },
  {
    "path": "lib/eth/abi/decoder.rb",
    "chars": 8483,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/abi/encoder.rb",
    "chars": 11845,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/abi/event.rb",
    "chars": 5617,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/abi/function.rb",
    "chars": 4179,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/abi/packed/encoder.rb",
    "chars": 7149,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/abi/type.rb",
    "chars": 10202,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/abi.rb",
    "chars": 5410,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/address.rb",
    "chars": 3211,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/api.rb",
    "chars": 8568,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/bls.rb",
    "chars": 2315,
    "preview": "# frozen_string_literal: true\n\nrequire \"bls\"\n\nmodule Eth\n  # Helper methods for interacting with BLS12-381 points and si"
  },
  {
    "path": "lib/eth/chain.rb",
    "chars": 6545,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/client/http.rb",
    "chars": 2341,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/client/ipc.rb",
    "chars": 1445,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/client/ws.rb",
    "chars": 9254,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/client.rb",
    "chars": 21035,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/constant.rb",
    "chars": 1950,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/contract/error.rb",
    "chars": 2127,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/contract/event.rb",
    "chars": 3270,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/contract/function.rb",
    "chars": 2642,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/contract/function_input.rb",
    "chars": 1357,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/contract/function_output.rb",
    "chars": 1376,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/contract/initializer.rb",
    "chars": 1401,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/contract.rb",
    "chars": 7603,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/eip712.rb",
    "chars": 8592,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/ens/coin_type.rb",
    "chars": 1432,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/ens/resolver.rb",
    "chars": 4503,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/ens.rb",
    "chars": 955,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/key/decrypter.rb",
    "chars": 3697,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/key/encrypter.rb",
    "chars": 6170,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/key.rb",
    "chars": 5945,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/rlp/decoder.rb",
    "chars": 4327,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/rlp/encoder.rb",
    "chars": 2702,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/rlp/sedes/big_endian_int.rb",
    "chars": 2742,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/rlp/sedes/binary.rb",
    "chars": 3824,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/rlp/sedes/list.rb",
    "chars": 3074,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/rlp/sedes.rb",
    "chars": 2627,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/rlp.rb",
    "chars": 1962,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/signature.rb",
    "chars": 6977,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/solidity.rb",
    "chars": 2897,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/tx/eip1559.rb",
    "chars": 14243,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/tx/eip2930.rb",
    "chars": 13734,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/tx/eip4844.rb",
    "chars": 15997,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/tx/eip7702.rb",
    "chars": 20560,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/tx/legacy.rb",
    "chars": 11632,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/tx.rb",
    "chars": 14804,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/unit.rb",
    "chars": 1668,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/util.rb",
    "chars": 8285,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth/version.rb",
    "chars": 961,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "lib/eth.rb",
    "chars": 1040,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "spec/eth/abi/decoder_spec.rb",
    "chars": 8908,
    "preview": "# -*- encoding : ascii-8bit -*-\n\nrequire \"spec_helper\"\n\ndescribe Abi::Decoder do\n  subject(:t_bool) { Abi::Type.parse \"b"
  },
  {
    "path": "spec/eth/abi/encoder_spec.rb",
    "chars": 10056,
    "preview": "# -*- encoding : ascii-8bit -*-\n\nrequire \"spec_helper\"\n\ndescribe Abi::Encoder do\n  subject(:t_bool) { Abi::Type.parse \"b"
  },
  {
    "path": "spec/eth/abi/event_spec.rb",
    "chars": 15931,
    "preview": "# -*- encoding : ascii-8bit -*-\n\nrequire \"spec_helper\"\n\ndescribe Abi::Event do\n  let(:erc20_abi_file) { File.read \"spec/"
  },
  {
    "path": "spec/eth/abi/function_spec.rb",
    "chars": 1383,
    "preview": "require \"spec_helper\"\n\ndescribe Abi::Function do\n  let(:erc20_abi_file) { File.read \"spec/fixtures/abi/ERC20.json\" }\n  s"
  },
  {
    "path": "spec/eth/abi/packed/encoder_spec.rb",
    "chars": 12152,
    "preview": "# -*- encoding : ascii-8bit -*-\n\nrequire \"spec_helper\"\n\ndescribe Abi::Packed::Encoder do\n  it \"encodes packed types\" do\n"
  },
  {
    "path": "spec/eth/abi/type_spec.rb",
    "chars": 8115,
    "preview": "# -*- encoding : ascii-8bit -*-\n\nrequire \"spec_helper\"\n\ndescribe Abi::Type do\n  describe \".initialize\" do\n    it \"can in"
  },
  {
    "path": "spec/eth/abi_spec.rb",
    "chars": 31400,
    "preview": "# -*- encoding : ascii-8bit -*-\n\nrequire \"spec_helper\"\n\ndescribe Abi do\n  describe \".encode .decode\" do\n\n    # load offi"
  },
  {
    "path": "spec/eth/address_spec.rb",
    "chars": 6380,
    "preview": "require \"spec_helper\"\n\ndescribe Address do\n  describe \".initialize\" do\n    # alice is initialized with an unprefixed add"
  },
  {
    "path": "spec/eth/bls_spec.rb",
    "chars": 1187,
    "preview": "# frozen_string_literal: true\n\nrequire \"spec_helper\"\n\nRSpec.describe Eth::Bls do\n  let(:priv_key) { \"0x01\" }\n  let(:mess"
  },
  {
    "path": "spec/eth/chain_spec.rb",
    "chars": 5905,
    "preview": "require \"spec_helper\"\n\ndescribe Chain do\n  context \"#CHAIN_ID\" do\n    it \"has EIP155 chain ids for mainnets, testnets, a"
  },
  {
    "path": "spec/eth/client/ws_spec.rb",
    "chars": 10734,
    "preview": "# Copyright (c) 2016-2025 The Ruby-Eth Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "spec/eth/client_spec.rb",
    "chars": 43005,
    "preview": "require \"spec_helper\"\n\ndescribe Client do\n\n  # run `geth --dev --http --wc --ipcpath /tmp/geth.ipc`\n  # to provide http,"
  },
  {
    "path": "spec/eth/constant_spec.rb",
    "chars": 1301,
    "preview": "# # -*- encoding : ascii-8bit -*-\n\nrequire \"spec_helper\"\n\ndescribe Eth::Constant do\n  describe \"#SYMBOLS\" do\n    it \"has"
  },
  {
    "path": "spec/eth/contract/error_spec.rb",
    "chars": 1272,
    "preview": "require \"spec_helper\"\n\ndescribe Contract do\n  let(:abi) do\n    [\n      { \"type\" => \"function\", \"name\" => \"foo\", \"inputs\""
  },
  {
    "path": "spec/eth/contract/event_spec.rb",
    "chars": 5382,
    "preview": "require \"spec_helper\"\n\ndescribe Contract::Event do\n  let(:path) { \"spec/fixtures/contracts/test_contract.sol\" }\n  subjec"
  },
  {
    "path": "spec/eth/contract/function_input_spec.rb",
    "chars": 770,
    "preview": "require \"spec_helper\"\n\ndescribe Contract::FunctionInput do\n  subject(:function_input) { Contract::FunctionInput.new({ \"n"
  },
  {
    "path": "spec/eth/contract/function_output_spec.rb",
    "chars": 780,
    "preview": "require \"spec_helper\"\n\ndescribe Contract::FunctionOutput do\n  subject(:function_output) { Contract::FunctionOutput.new({"
  },
  {
    "path": "spec/eth/contract/function_spec.rb",
    "chars": 3215,
    "preview": "require \"spec_helper\"\n\ndescribe Contract::Function do\n  let(:erc20_abi_file) { File.read \"spec/fixtures/abi/ERC20.json\" "
  },
  {
    "path": "spec/eth/contract/initializer_spec.rb",
    "chars": 703,
    "preview": "require \"spec_helper\"\n\ndescribe Contract::Initializer do\n  subject(:file) { \"spec/fixtures/contracts/greeter.sol\" }\n  su"
  },
  {
    "path": "spec/eth/contract_spec.rb",
    "chars": 6897,
    "preview": "require \"spec_helper\"\n\ndescribe Contract do\n  subject(:solc) { Eth::Solidity.new }\n  subject(:contract) { solc.compile(f"
  },
  {
    "path": "spec/eth/eip712_spec.rb",
    "chars": 12327,
    "preview": "require \"spec_helper\"\n\ndescribe Eip712 do\n\n  # The EIP-712 domain specification descriptor.\n  subject(:eip712_domain) {\n"
  },
  {
    "path": "spec/eth/ens/coin_type_spec.rb",
    "chars": 470,
    "preview": "require \"spec_helper\"\n\ndescribe Ens::CoinType do\n  it \"knows some coin slip-44 types\" do\n    expect(Ens::CoinType::BITCO"
  },
  {
    "path": "spec/eth/ens/resolver_spec.rb",
    "chars": 2564,
    "preview": "require \"spec_helper\"\n\ndescribe Ens::Resolver do\n\n  # public rpc\n  let(:drpc_api) { \"https://eth.drpc.org\" }\n  subject(:"
  },
  {
    "path": "spec/eth/ens_spec.rb",
    "chars": 243,
    "preview": "require \"spec_helper\"\n\ndescribe Ens do\n  it \"has EIP155 chain ids for mainnets, testnets, and devnets\" do\n    # Chain ID"
  },
  {
    "path": "spec/eth/key/decrypter_spec.rb",
    "chars": 2216,
    "preview": "require \"spec_helper\"\n\ndescribe Key::Decrypter do\n  def read_key_fixture(path)\n    File.read \"./spec/fixtures/keys/#{pat"
  },
  {
    "path": "spec/eth/key/encrypter_spec.rb",
    "chars": 4585,
    "preview": "require \"spec_helper\"\n\n# These test vectors are specified in the ethereum wiki:\n# https://github.com/ethereum/wiki/wiki/"
  },
  {
    "path": "spec/eth/key_spec.rb",
    "chars": 8951,
    "preview": "require \"spec_helper\"\n\ndescribe Key do\n  describe \".initialize\" do\n    subject(:alice) { Key.new }\n    subject(:bob) { K"
  },
  {
    "path": "spec/eth/rlp/sedes/big_endian_int_spec.rb",
    "chars": 2132,
    "preview": "# -*- encoding : ascii-8bit -*-\n\nrequire \"spec_helper\"\n\ndescribe Rlp::Sedes::BigEndianInt do\n  subject(:integers) {\n    "
  },
  {
    "path": "spec/eth/rlp/sedes/binary_spec.rb",
    "chars": 482,
    "preview": "# -*- encoding : ascii-8bit -*-\n\nrequire \"spec_helper\"\n\ndescribe Rlp::Sedes::Binary do\n  it \"does serialize fixed length"
  },
  {
    "path": "spec/eth/rlp/sedes/list_spec.rb",
    "chars": 1101,
    "preview": "# -*- encoding : ascii-8bit -*-\n\nrequire \"spec_helper\"\n\ndescribe Rlp::Sedes::List do\n  subject(:l1) { Rlp::Sedes::List.n"
  },
  {
    "path": "spec/eth/rlp/sedes_spec.rb",
    "chars": 885,
    "preview": "# -*- encoding : ascii-8bit -*-\n\nrequire \"spec_helper\"\n\ndescribe Rlp::Sedes do\n  describe \"inference\" do\n    subject(:pa"
  },
  {
    "path": "spec/eth/rlp_spec.rb",
    "chars": 3303,
    "preview": "# -*- encoding : ascii-8bit -*-\n\nrequire \"spec_helper\"\n\ndescribe Rlp do\n  describe \".encode .decode\" do\n\n    # load offi"
  },
  {
    "path": "spec/eth/signature_spec.rb",
    "chars": 16180,
    "preview": "require \"spec_helper\"\n\ndescribe Signature do\n  describe \".prefix_message\" do\n    it \"can properly prefix messages\" do\n  "
  },
  {
    "path": "spec/eth/solidity_spec.rb",
    "chars": 3322,
    "preview": "require \"spec_helper\"\n\ndescribe Solidity do\n  it \"finds a solc compiler\" do\n    # This fails if no `solc` is in the $PAT"
  },
  {
    "path": "spec/eth/tx/eip1559_spec.rb",
    "chars": 12787,
    "preview": "# -*- encoding : ascii-8bit -*-\n\nrequire \"spec_helper\"\n\ndescribe Tx::Eip1559 do\n\n  # ref https://goerli.etherscan.io/tx/"
  },
  {
    "path": "spec/eth/tx/eip2930_spec.rb",
    "chars": 19636,
    "preview": "# -*- encoding : ascii-8bit -*-\n\nrequire \"spec_helper\"\n\ndescribe Tx::Eip2930 do\n  # ref https://goerli.etherscan.io/tx/0"
  },
  {
    "path": "spec/eth/tx/eip4844_spec.rb",
    "chars": 9924,
    "preview": "# -*- encoding : ascii-8bit -*-\n\nrequire \"spec_helper\"\n\ndescribe Tx::Eip4844 do\n  subject(:blob_hashes) { [\"0x\" + \"11\" *"
  },
  {
    "path": "spec/eth/tx/eip7702_spec.rb",
    "chars": 22066,
    "preview": "# -*- encoding : ascii-8bit -*-\n\nrequire \"spec_helper\"\n\ndescribe Tx::Eip7702 do\n  subject(:anvil) {\n    31337.freeze\n  }"
  },
  {
    "path": "spec/eth/tx/legacy_spec.rb",
    "chars": 18406,
    "preview": "# -*- encoding : ascii-8bit -*-\n\nrequire \"spec_helper\"\n\ndescribe Tx::Legacy do\n  subject(:tx) {\n    Tx.new({\n      nonce"
  },
  {
    "path": "spec/eth/tx_spec.rb",
    "chars": 14482,
    "preview": "require \"spec_helper\"\n\ndescribe Tx do\n  context \"#GAS\" do\n    it \"defines gas limits\" do\n      expect(Tx::DEFAULT_GAS_LI"
  },
  {
    "path": "spec/eth/unit_spec.rb",
    "chars": 506,
    "preview": "require \"spec_helper\"\n\ndescribe Unit do\n  context \"#ETHER\" do\n    it \"has constants for all common Ether units\" do\n     "
  },
  {
    "path": "spec/eth/util_spec.rb",
    "chars": 11263,
    "preview": "# -*- encoding : ascii-8bit -*-\n\nrequire \"spec_helper\"\n\ndescribe Util do\n  describe \".public_key_to_address\" do\n    it \""
  },
  {
    "path": "spec/eth_spec.rb",
    "chars": 156,
    "preview": "require \"spec_helper\"\n\ndescribe Eth do\n  it \"0.5.17 works\" do\n\n    # placeholder to set up spec in future\n    expect(Eth"
  },
  {
    "path": "spec/fixtures/abi/ENSRegistryWithFallback.json",
    "chars": 10136,
    "preview": "[\n    {\n        \"inputs\":[\n            {\n                \"internalType\":\"contract ENS\",\n                \"name\":\"_old\",\n "
  },
  {
    "path": "spec/fixtures/abi/ERC1155.json",
    "chars": 5666,
    "preview": "[\n  {\n    \"anonymous\": false,\n    \"inputs\": [\n      {\n        \"indexed\": true,\n        \"internalType\": \"address\",\n      "
  },
  {
    "path": "spec/fixtures/abi/ERC20.json",
    "chars": 3385,
    "preview": "[\n  {\n    \"anonymous\": false,\n    \"inputs\": [\n      {\n        \"indexed\": true,\n        \"internalType\": \"address\",\n      "
  },
  {
    "path": "spec/fixtures/abi/ERC721.json",
    "chars": 5398,
    "preview": "[\n  {\n    \"anonymous\": false,\n    \"inputs\": [\n      {\n        \"indexed\": true,\n        \"internalType\": \"address\",\n      "
  },
  {
    "path": "spec/fixtures/abi/Tuple.json",
    "chars": 2326,
    "preview": "[\n  {\n    \"inputs\": [\n      {\n        \"components\": [\n          {\n            \"internalType\": \"string\",\n            \"nam"
  },
  {
    "path": "spec/fixtures/abi/Tuple2.json",
    "chars": 2990,
    "preview": "[\n  {\n    \"inputs\": [\n      {\n        \"components\": [\n          {\n            \"components\": [\n              {\n          "
  },
  {
    "path": "spec/fixtures/abi/ethers.json",
    "chars": 7014464,
    "preview": "[\n {\n  \"name\": \"random-((string))\",\n  \"type\": \"((string))\",\n  \"value\": [\n   [\n    \"Moo é🚀 éooM🚀🚀ooMoo🚀M🚀ooooMé🚀éé🚀é 🚀M 🚀"
  },
  {
    "path": "spec/fixtures/contracts/address_storage.sol",
    "chars": 487,
    "preview": "// SPDX-License-Identifier: Apache-2.0\n\npragma solidity ^0.8;\n\ncontract AddressStorage {\n\n  address myAddress;\n  address"
  },
  {
    "path": "spec/fixtures/contracts/deposit.sol",
    "chars": 8067,
    "preview": "// SPDX-License-Identifier: CC0-1.0\n\npragma solidity ^0.8;\n\n// Do not use this contract in production! It's untested and"
  },
  {
    "path": "spec/fixtures/contracts/dummy.sol",
    "chars": 241,
    "preview": "// SPDX-License-Identifier: Apache-2.0\n\npragma solidity ^0.8;\n\ncontract Dummy {\n  uint number;\n  function set(uint x) pu"
  },
  {
    "path": "spec/fixtures/contracts/erc20.sol",
    "chars": 4969,
    "preview": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (v4.8.0 - simplified)\n\npragma solidity ^0.8;\n\n// Do not use th"
  },
  {
    "path": "spec/fixtures/contracts/error.sol",
    "chars": 98,
    "preview": "// SPDX-License-Identifier: Apache-2.0\n\npragma solidity ^0.8;\n\ncontract Error {\n  noint number;\n}\n"
  },
  {
    "path": "spec/fixtures/contracts/greeter.sol",
    "chars": 831,
    "preview": "// SPDX-License-Identifier: Apache-2.0\n\npragma solidity ^0.8;\n\ncontract Mortal {\n\n  // defines the owner of type payable"
  },
  {
    "path": "spec/fixtures/contracts/signer.sol",
    "chars": 1132,
    "preview": "// SPDX-License-Identifier: Apache-2.0\n\npragma solidity ^0.8;\n\nlibrary LibBytes {\n  function readBytes32(\n    bytes memo"
  },
  {
    "path": "spec/fixtures/contracts/simple_registry.sol",
    "chars": 290,
    "preview": "// SPDX-License-Identifier: Apache-2.0\n\npragma solidity ^0.8;\n\ncontract SimpleRegistry {\n  uint number1;\n  uint number2;"
  },
  {
    "path": "spec/fixtures/contracts/test_contract.sol",
    "chars": 835,
    "preview": "// SPDX-License-Identifier: Apache-2.0\n\npragma solidity ^0.8;\n\ncontract TestContract {\n\n    address payable public owner"
  },
  {
    "path": "spec/fixtures/contracts/tuple.sol",
    "chars": 473,
    "preview": "// SPDX-License-Identifier: Apache-2.0\n\npragma solidity ^0.8;\n\ncontract Tuple {\n    struct Tuple1 {\n        string var1;"
  },
  {
    "path": "spec/fixtures/contracts/tuple2.sol",
    "chars": 460,
    "preview": "// SPDX-License-Identifier: Apache-2.0\n\npragma solidity ^0.8;\n\ncontract Tuple2 {\n    struct  Nar {\n        Nuu nuu;\n    "
  },
  {
    "path": "spec/fixtures/keys/testingtesting.json",
    "chars": 491,
    "preview": "{\"version\":3,\"id\":\"a8c1108e-033d-4d41-b5ea-e26f620b9eda\",\"address\":\"65bcb68d4c73e163c69eea056d63bb09faacdd8e\",\"Crypto\":{"
  },
  {
    "path": "spec/fixtures/keys/testpassword.json",
    "chars": 494,
    "preview": "{ \"crypto\" : { \"cipher\" : \"aes-128-ctr\", \"cipherparams\" : { \"iv\" : \"6087dab2f9fdbbfaddc31a909735c1e6\" }, \"ciphertext\" : "
  },
  {
    "path": "spec/fixtures/keys/testunknownkdf.json",
    "chars": 500,
    "preview": "{\"version\":3,\"id\":\"a8c1108e-033d-4d41-b5ea-e26f620b9eda\",\"address\":\"65bcb68d4c73e163c69eea056d63bb09faacdd8e\",\"Crypto\":{"
  },
  {
    "path": "spec/spec_helper.rb",
    "chars": 380,
    "preview": "# use the local version of the code instead of a globally installed gem\n$LOAD_PATH.unshift File.expand_path(\"../../lib\","
  }
]

About this extraction

This page contains the full source code of the q9f/eth.rb GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 136 files (7.4 MB), approximately 2.0M tokens, and a symbol index with 550 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!