Showing preview only (7,090K chars total). Download the full file or copy to clipboard to get everything.
Repository: lmittmann/w3
Branch: main
Commit: 856b989ac237
Files: 263
Total size: 76.8 MB
Directory structure:
gitextract_vxq391jt/
├── .gitattributes
├── .github/
│ ├── dependabot.yml
│ └── workflows/
│ ├── doc.yml
│ └── go.yml
├── .gitignore
├── LICENSE
├── README.md
├── client.go
├── client_test.go
├── docs/
│ ├── components/
│ │ └── DocLink.jsx
│ ├── next.config.js
│ ├── package.json
│ ├── pages/
│ │ ├── 404.mdx
│ │ ├── _app.js
│ │ ├── _meta.js
│ │ ├── examples/
│ │ │ ├── _meta.js
│ │ │ └── index.mdx
│ │ ├── examples.mdx
│ │ ├── helper-abi.mdx
│ │ ├── helper-utils.mdx
│ │ ├── index.mdx
│ │ ├── rpc-extension.mdx
│ │ ├── rpc-methods/
│ │ │ ├── _meta.js
│ │ │ ├── admin.mdx
│ │ │ ├── debug.mdx
│ │ │ ├── eth.mdx
│ │ │ ├── net.mdx
│ │ │ ├── txpool.mdx
│ │ │ └── web3.mdx
│ │ ├── rpc-methods.mdx
│ │ ├── rpc-overview.mdx
│ │ ├── style.css
│ │ ├── vm-overview.mdx
│ │ ├── vm-testing.mdx
│ │ └── vm-tracing.mdx
│ ├── postcss.config.cjs
│ ├── public/
│ │ ├── _redirects
│ │ └── robots.txt
│ ├── tailwind.config.js
│ └── theme.config.jsx
├── event.go
├── event_test.go
├── example_test.go
├── func.go
├── func_test.go
├── go.mod
├── go.sum
├── internal/
│ ├── abi/
│ │ ├── arguments.go
│ │ ├── arguments_test.go
│ │ ├── copy.go
│ │ ├── copy_test.go
│ │ ├── doc.go
│ │ ├── lexer.go
│ │ ├── lexer_test.go
│ │ ├── parser.go
│ │ ├── parser_test.go
│ │ ├── tuple.go
│ │ └── tuple_test.go
│ ├── cmp.go
│ ├── cmp_test.go
│ ├── crypto/
│ │ └── keccak.go
│ ├── fourbyte/
│ │ ├── events.go
│ │ ├── events.txt
│ │ ├── fourbyte.go
│ │ ├── funcs.go
│ │ ├── funcs.txt
│ │ └── gen.go
│ ├── hexutil/
│ │ ├── bytes.go
│ │ ├── bytes_test.go
│ │ ├── hash.go
│ │ └── hash_test.go
│ ├── mod/
│ │ ├── root.go
│ │ └── root_test.go
│ └── module/
│ ├── factory.go
│ ├── util.go
│ └── util_test.go
├── module/
│ ├── admin/
│ │ ├── admin.go
│ │ ├── admin_test.go
│ │ └── testdata/
│ │ ├── add_peer.golden
│ │ ├── add_trusted_peer.golden
│ │ ├── node_info.golden
│ │ ├── remove_peer.golden
│ │ └── remove_trusted_peer.golden
│ ├── debug/
│ │ ├── call_trace.go
│ │ ├── call_trace_test.go
│ │ ├── doc.go
│ │ ├── testdata/
│ │ │ ├── traceCall.golden
│ │ │ ├── traceCall_callTracer.golden
│ │ │ ├── traceTx__1150000_0.golden
│ │ │ ├── traceTx__12244000_0.golden
│ │ │ └── traceTx_revertReason.golden
│ │ ├── trace.go
│ │ └── trace_test.go
│ ├── eth/
│ │ ├── balance.go
│ │ ├── balance_test.go
│ │ ├── block.go
│ │ ├── block_number.go
│ │ ├── block_number_test.go
│ │ ├── block_test.go
│ │ ├── call.go
│ │ ├── call_test.go
│ │ ├── chain_id.go
│ │ ├── chain_id_test.go
│ │ ├── code.go
│ │ ├── code_test.go
│ │ ├── doc.go
│ │ ├── gas_price.go
│ │ ├── gas_price_test.go
│ │ ├── gas_tip_cap.go
│ │ ├── gas_tip_cap_test.go
│ │ ├── get_logs.go
│ │ ├── get_logs_test.go
│ │ ├── storage_at.go
│ │ ├── storage_at_test.go
│ │ ├── subscribe.go
│ │ ├── syncing.go
│ │ ├── syncing_test.go
│ │ ├── testdata/
│ │ │ ├── block_number.golden
│ │ │ ├── block_transaction_count_by_hash__0x00.golden
│ │ │ ├── block_transaction_count_by_hash__15050000.golden
│ │ │ ├── block_transaction_count_by_number__15050000.golden
│ │ │ ├── call_func.golden
│ │ │ ├── call_func__overrides.golden
│ │ │ ├── chain_id.golden
│ │ │ ├── create_access_list.golden
│ │ │ ├── estimate_gas.golden
│ │ │ ├── gas_price.golden
│ │ │ ├── gas_tip_cap.golden
│ │ │ ├── get_balance.golden
│ │ │ ├── get_balance__at_block.golden
│ │ │ ├── get_block_by_hash__0x00.golden
│ │ │ ├── get_block_by_hash__1.golden
│ │ │ ├── get_block_by_hash__12965000.golden
│ │ │ ├── get_block_by_hash__18000000.golden
│ │ │ ├── get_block_by_hash__46147.golden
│ │ │ ├── get_block_by_number__1.golden
│ │ │ ├── get_block_by_number__12965000.golden
│ │ │ ├── get_block_by_number__46147.golden
│ │ │ ├── get_block_by_number__999999999.golden
│ │ │ ├── get_block_receipts.golden
│ │ │ ├── get_code.golden
│ │ │ ├── get_logs.golden
│ │ │ ├── get_storage_at.golden
│ │ │ ├── get_storage_at__number.golden
│ │ │ ├── get_transaction_by_block_hash_and_index.golden
│ │ │ ├── get_transaction_by_block_hash_and_index__300.golden
│ │ │ ├── get_transaction_by_block_number_and_index.golden
│ │ │ ├── get_transaction_by_hash__0x00.golden
│ │ │ ├── get_transaction_by_hash__type0.golden
│ │ │ ├── get_transaction_by_hash__type2.golden
│ │ │ ├── get_transaction_count.golden
│ │ │ ├── get_transaction_receipt.golden
│ │ │ ├── get_transaction_receipt_0x00.golden
│ │ │ ├── send_raw_transaction.golden
│ │ │ ├── syncing__false.golden
│ │ │ ├── syncing__true.golden
│ │ │ ├── uncle_by_hash_and_index__15050036.golden
│ │ │ ├── uncle_by_hash_and_index__15050036_1.golden
│ │ │ ├── uncle_by_number_and_index__15050036.golden
│ │ │ ├── uncle_count_by_hash__15050036.golden
│ │ │ └── uncle_count_by_number__15050036.golden
│ │ ├── tx.go
│ │ ├── tx_test.go
│ │ ├── uncle.go
│ │ └── uncle_test.go
│ ├── net/
│ │ ├── net.go
│ │ ├── net_test.go
│ │ └── testdata/
│ │ ├── listening.golden
│ │ ├── peer_count.golden
│ │ └── version.golden
│ ├── txpool/
│ │ ├── content.go
│ │ ├── content_test.go
│ │ ├── doc.go
│ │ ├── status.go
│ │ ├── status_test.go
│ │ └── testdata/
│ │ ├── content.golden
│ │ ├── contentFrom.golden
│ │ └── status.golden
│ └── web3/
│ ├── testdata/
│ │ ├── client_version.golden
│ │ └── client_version__err.golden
│ ├── web3.go
│ └── web3_test.go
├── rpctest/
│ ├── server.go
│ └── test_case.go
├── testdata/
│ └── w3vm/
│ ├── 1_12243997.json
│ ├── 1_12243998.json
│ ├── 1_12243999.json
│ ├── 1_12244000.json
│ ├── 1_12964997.json
│ ├── 1_12964998.json
│ ├── 1_12964999.json
│ ├── 1_12965000.json
│ ├── 1_13772997.json
│ ├── 1_13772998.json
│ ├── 1_13772999.json
│ ├── 1_13773000.json
│ ├── 1_15049997.json
│ ├── 1_15049998.json
│ ├── 1_15049999.json
│ ├── 1_15050000.json
│ ├── 1_15537391.json
│ ├── 1_15537392.json
│ ├── 1_15537393.json
│ ├── 1_15537394.json
│ ├── 1_17034867.json
│ ├── 1_17034868.json
│ ├── 1_17034869.json
│ ├── 1_17034870.json
│ ├── 1_18999999.json
│ ├── 1_19000000.json
│ ├── 1_19000001.json
│ ├── 1_19000002.json
│ ├── 1_19000003.json
│ ├── 1_19000004.json
│ ├── 1_19000005.json
│ ├── 1_19000006.json
│ ├── 1_19000007.json
│ ├── 1_19000008.json
│ ├── 1_19426484.json
│ ├── 1_19426485.json
│ ├── 1_19426486.json
│ ├── 1_19426487.json
│ ├── 1_19999999.json
│ ├── 1_4369997.json
│ ├── 1_4369998.json
│ ├── 1_4369999.json
│ ├── 1_4370000.json
│ ├── 1_7279997.json
│ ├── 1_7279998.json
│ ├── 1_7279999.json
│ ├── 1_7280000.json
│ ├── 1_9068997.json
│ ├── 1_9068998.json
│ ├── 1_9068999.json
│ ├── 1_9069000.json
│ ├── 1_9199997.json
│ ├── 1_9199998.json
│ ├── 1_9199999.json
│ ├── 1_9200000.json
│ ├── 1_header_hashes.json
│ └── contracts.json
├── util.go
├── util_test.go
├── w3types/
│ ├── interfaces.go
│ ├── interfaces_test.go
│ ├── message.go
│ ├── rpc.go
│ ├── rpc_test.go
│ ├── state.go
│ └── state_test.go
└── w3vm/
├── bench_test.go
├── db.go
├── example_test.go
├── fetcher.go
├── fetcher_test.go
├── hooks/
│ └── call_tracer.go
├── receipt.go
├── testdata/
│ ├── burntpix.genesis.json
│ └── weth9.bytecode
├── util.go
├── util_test.go
├── vm.go
└── vm_test.go
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
testdata/ linguist-generated=true
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "daily"
================================================
FILE: .github/workflows/doc.yml
================================================
name: Doc
on:
push:
branches: [main]
tags: ["v*"]
pull_request:
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- run: bun install
working-directory: ./docs
- run: bun run build
working-directory: ./docs
- name: upload Pages artifact
if: github.ref_type == 'tag'
uses: actions/upload-pages-artifact@v3
with:
path: ./docs/out
deploy:
name: Deploy
needs: build
if: github.ref_type == 'tag'
runs-on: ubuntu-latest
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: deploy to GitHub pages
id: deployment
uses: actions/deploy-pages@v4
================================================
FILE: .github/workflows/go.yml
================================================
name: Go
on:
push:
branches:
- main
pull_request:
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version: stable
- name: fmt
run: diff -u <(echo -n) <(gofmt -s -d .)
- name: vet
run: go vet ./...
- name: staticcheck
run: go run honnef.co/go/tools/cmd/staticcheck@latest ./...
- name: tidy
run: go mod tidy -diff
test:
name: Test
runs-on: ubuntu-latest
env:
RPC_MAINNET: ${{ secrets.RPC_MAINNET }}
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version-file: go.mod
- name: test
run: go test -short -covermode atomic -coverprofile=covprofile ./...
- name: goveralls
env:
COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: go run github.com/mattn/goveralls@latest -coverprofile=covprofile -service=github
================================================
FILE: .gitignore
================================================
# files
LOCK
# dirs
.next/
node_modules/
out/
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2022 lmittmann
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# `w3`: Enhanced Ethereum Integration for Go
[](https://pkg.go.dev/github.com/lmittmann/w3)
[](https://goreportcard.com/report/github.com/lmittmann/w3)
[](https://coveralls.io/github/lmittmann/w3?branch=main)
[](https://github.com/lmittmann/w3/releases)
[](https://t.me/w3_golang)
<img src="https://w3.cool/gopher.png" align="right" alt="W3 Gopher" width="158" height="224">
`w3` is your toolbelt for integrating with Ethereum in Go. Closely linked to `go‑ethereum`, it provides an ergonomic wrapper for working with **RPC**, **ABI's**, and the **EVM**.
```
go get github.com/lmittmann/w3
```
## At a Glance
* Use `w3.Client` to connect to an RPC endpoint. The client features batch request support for up to **80x faster requests** and easy extendibility. [learn more ↗](#rpc-client)
* Use `w3vm.VM` to simulate EVM execution with optional tracing and Mainnet state forking, or test Smart Contracts. [learn more ↗](#vm)
* Use `w3.Func` and `w3.Event` to create ABI bindings from Solidity function and event signatures. [learn more ↗](#abi-bindings)
* Use `w3.A`, `w3.H`, and many other utility functions to parse addresses, hashes, and other common types from strings. [learn more ↗](#utils)
## Sponsors
<picture>
<source media="(prefers-color-scheme: dark)" srcset="docs/public/assets/ef-logo-dark.svg">
<source media="(prefers-color-scheme: light)" srcset="docs/public/assets/ef-logo.svg">
<img src="docs/public/assets/ef-logo.svg" alt="ef logo" width="256" height="auto">
</picture>
## Getting Started
### RPC Client
[`w3.Client`](https://pkg.go.dev/github.com/lmittmann/w3#Client) is a batch request focused RPC client that can be used to connect to an Ethereum node via HTTP, WebSocket, or IPC. Its modular API allows to create custom RPC method integrations that can be used alongside the common methods implemented by this package.
**Example:** Batch Request ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-BatchEOAState))
```go
// 1. Connect to an RPC endpoint
client, err := w3.Dial("https://eth.llamarpc.com")
if err != nil {
// handle error
}
defer client.Close()
// 2. Make a batch request
var (
balance *big.Int
nonce uint64
)
if err := client.Call(
eth.Balance(addr, nil).Returns(&balance),
eth.Nonce(addr, nil).Returns(&nonce),
); err != nil {
// handle error
}
```
> [!NOTE]
> #### Why send batch requests?
> Most of the time you need to call multiple RPC methods to get the data you need. When you make separate requests per RPC call you need a single round trip to the server for each call. This can be slow, especially for remote endpoints. Batching multiple RPC calls into a single request only requires a single round trip, and speeds up RPC calls significantly.
#### Error Handling
If one or more calls in a batch request fail, `Client.Call` returns an error of type [`w3.CallErrors`](https://pkg.go.dev/github.com/lmittmann/w3#CallErrors).
**Example:** Check which RPC calls failed in a batch request ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-BatchHandleError))
```go
var batchErr w3.CallErrors
if err := client.Call(calls...); errors.As(err, &batchErr) {
// handle call errors
} else if err != nil {
// handle other errors
}
```
#### Learn More
* List of supported [**RPC methods**](#rpc-methods)
* Learn how to create [**custom RPC method bindings**](#custom-rpc-method-bindings)
### VM
[`w3vm.VM`](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#VM) is a high-level EVM environment with a simple but powerful API to simulate EVM execution, test Smart Contracts, or trace transactions. It supports Mainnet state forking via RPC and state caching for faster testing.
**Example:** Simulate an Uniswap v3 swap ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-UniswapV3Swap))
```go
// 1. Create a VM that forks the Mainnet state from the latest block,
// disables the base fee, and has a fake WETH balance and approval for the router
vm, err := w3vm.New(
w3vm.WithFork(client, nil),
w3vm.WithNoBaseFee(),
w3vm.WithState(w3types.State{
addrWETH: {Storage: w3types.Storage{
w3vm.WETHBalanceSlot(addrEOA): common.BigToHash(w3.I("1 ether")),
w3vm.WETHAllowanceSlot(addrEOA, addrRouter): common.BigToHash(w3.I("1 ether")),
}},
}),
)
if err != nil {
// handle error
}
// 2. Simulate a Uniswap v3 swap
receipt, err := vm.Apply(&w3types.Message{
From: addrEOA,
To: &addrRouter,
Func: funcExactInput,
Args: []any{&ExactInputParams{
Path: encodePath(addrWETH, 500, addrUNI),
Recipient: addrEOA,
Deadline: big.NewInt(time.Now().Unix()),
AmountIn: w3.I("1 ether"),
AmountOutMinimum: w3.Big0,
}},
})
if err != nil {
// handle error
}
// 3. Decode output amount
var amountOut *big.Int
if err := receipt.DecodeReturns(&amountOut); err != nil {
// handle error
}
```
### ABI Bindings
ABI bindings in `w3` are specified for individual functions using Solidity syntax and are usable for any contract that supports that function.
**Example:** ABI binding for the ERC20 `balanceOf` function ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-NewFunc-BalanceOf))
```go
funcBalanceOf := w3.MustNewFunc("balanceOf(address)", "uint256")
```
**Example:** ABI binding for the Uniswap v4 `swap` function ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-NewFunc-UniswapV4Swap))
```go
funcSwap := w3.MustNewFunc(`swap(
(address currency0, address currency1, uint24 fee, int24 tickSpacing, address hooks) key,
(bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96) params,
bytes hookData
)`, "int256 delta")
```
A [`Func`](https://pkg.go.dev/github.com/lmittmann/w3#Func) can be used to
* encode arguments to the contracts input data ([`Func.EncodeArgs`](https://pkg.go.dev/github.com/lmittmann/w3#Func.EncodeArgs)),
* decode arguments from the contracts input data ([`Func.DecodeArgs`](https://pkg.go.dev/github.com/lmittmann/w3#Func.DecodeArgs)), and
* decode returns from the contracts output data ([`Func.DecodeReturns`](https://pkg.go.dev/github.com/lmittmann/w3#Func.DecodeReturns)).
### Utils
Static addresses, hashes, bytes or integers can be parsed from (hex-)strings with the following utility functions that panic if the string is not valid.
```go
addr := w3.A("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
hash := w3.H("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3")
bytes := w3.B("0x27c5342c")
amount := w3.I("12.34 ether")
```
Use [go-ethereum/common](https://pkg.go.dev/github.com/ethereum/go-ethereum/common) to parse strings that may not be valid instead.
## RPC Methods
List of supported RPC methods for [`w3.Client`](https://pkg.go.dev/github.com/lmittmann/w3#Client).
### [`eth`](https://pkg.go.dev/github.com/lmittmann/w3/module/eth)
| Method | Go Code
| :---------------------------------------- | :-------
| `eth_blockNumber` | `eth.BlockNumber().Returns(blockNumber **big.Int)`
| `eth_call` | `eth.Call(msg *w3types.Message, blockNumber *big.Int, overrides w3types.State).Returns(output *[]byte)`<br>`eth.CallFunc(contract common.Address, f w3types.Func, args ...any).Returns(returns ...any)`
| `eth_chainId` | `eth.ChainID().Returns(chainID *uint64)`
| `eth_createAccessList` | `eth.AccessList(msg *w3types.Message, blockNumber *big.Int).Returns(resp **eth.AccessListResponse)`
| `eth_estimateGas` | `eth.EstimateGas(msg *w3types.Message, blockNumber *big.Int).Returns(gas *uint64)`
| `eth_gasPrice` | `eth.GasPrice().Returns(gasPrice **big.Int)`
| `eth_maxPriorityFeePerGas` | `eth.GasTipCap().Returns(gasTipCap **big.Int)`
| `eth_getBalance` | `eth.Balance(addr common.Address, blockNumber *big.Int).Returns(balance **big.Int)`
| `eth_getBlockByHash` | `eth.BlockByHash(hash common.Hash).Returns(block *types.Block)`<br>`eth.HeaderByHash(hash common.Hash).Returns(header **types.Header)`
| `eth_getBlockByNumber` | `eth.BlockByNumber(number *big.Int).Returns(block *types.Block)`<br>`eth.HeaderByNumber(number *big.Int).Returns(header **types.Header)`
| `eth_getBlockReceipts` | `eth.BlockReceipts(blockNumber *big.Int).Returns(receipts *types.Receipts)`
| `eth_getBlockTransactionCountByHash` | `eth.BlockTxCountByHash(hash common.Hash).Returns(count *uint)`
| `eth_getBlockTransactionCountByNumber` | `eth.BlockTxCountByNumber(number *big.Int).Returns(count *uint)`
| `eth_getCode` | `eth.Code(addr common.Address, blockNumber *big.Int).Returns(code *[]byte)`
| `eth_getLogs` | `eth.Logs(q ethereum.FilterQuery).Returns(logs *[]types.Log)`
| `eth_getStorageAt` | `eth.StorageAt(addr common.Address, slot common.Hash, blockNumber *big.Int).Returns(storage *common.Hash)`
| `eth_getTransactionByHash` | `eth.Tx(hash common.Hash).Returns(tx **types.Transaction)`
| `eth_getTransactionByBlockHashAndIndex` | `eth.TxByBlockHashAndIndex(blockHash common.Hash, index uint).Returns(tx **types.Transaction)`
| `eth_getTransactionByBlockNumberAndIndex` | `eth.TxByBlockNumberAndIndex(blockNumber *big.Int, index uint).Returns(tx **types.Transaction)`
| `eth_getTransactionCount` | `eth.Nonce(addr common.Address, blockNumber *big.Int).Returns(nonce *uint)`
| `eth_getTransactionReceipt` | `eth.TxReceipt(txHash common.Hash).Returns(receipt **types.Receipt)`
| `eth_sendRawTransaction` | `eth.SendRawTx(rawTx []byte).Returns(hash *common.Hash)`<br>`eth.SendTx(tx *types.Transaction).Returns(hash *common.Hash)`
| `eth_getUncleByBlockHashAndIndex` | `eth.UncleByBlockHashAndIndex(hash common.Hash, index uint).Returns(uncle **types.Header)`
| `eth_getUncleByBlockNumberAndIndex` | `eth.UncleByBlockNumberAndIndex(number *big.Int, index uint).Returns(uncle **types.Header)`
| `eth_getUncleCountByBlockHash` | `eth.UncleCountByBlockHash(hash common.Hash).Returns(count *uint)`
| `eth_getUncleCountByBlockNumber` | `eth.UncleCountByBlockNumber(number *big.Int).Returns(count *uint)`
| `eth_syncing` | `eth.Syncing().Returns(syncing *bool)`
### [`debug`](https://pkg.go.dev/github.com/lmittmann/w3/module/debug)
| Method | Go Code
| :----------------------- | :-------
| `debug_traceCall` | `debug.TraceCall(msg *w3types.Message, blockNumber *big.Int, config *debug.TraceConfig).Returns(trace **debug.Trace)`<br>`debug.CallTraceCall(msg *w3types.Message, blockNumber *big.Int, overrides w3types.State).Returns(trace **debug.CallTrace)`
| `debug_traceTransaction` | `debug.TraceTx(txHash common.Hash, config *debug.TraceConfig).Returns(trace **debug.Trace)`<br>`debug.CallTraceTx(txHash common.Hash, overrides w3types.State).Returns(trace **debug.CallTrace)`
### [`txpool`](https://pkg.go.dev/github.com/lmittmann/w3/module/txpool)
| Method | Go Code
| :--------------------| :-------
| `txpool_content` | `txpool.Content().Returns(resp **txpool.ContentResponse)`
| `txpool_contentFrom` | `txpool.ContentFrom(addr common.Address).Returns(resp **txpool.ContentFromResponse)`
| `txpool_status` | `txpool.Status().Returns(resp **txpool.StatusResponse)`
### [`admin`](https://pkg.go.dev/github.com/lmittmann/w3/module/admin)
| Method | Go Code
| :------------------------ | :-------
| `admin_addPeer` | `admin.AddPeer(url *enode.Node).Returns(resp *bool)`
| `admin_removePeer` | `admin.RemovePeer(url *enode.Node).Returns(resp *bool)`
| `admin_addTrustedPeer` | `admin.AddTrustedPeer(url *enode.Node).Returns(resp *bool)`
| `admin_removeTrustedPeer` | `admin.RemoveTrustedPeer(url *enode.Node).Returns(resp *bool)`
| `admin_nodeInfo` | `admin.NodeInfo().Returns(resp **admin.NodeInfoResponse)`
### [`net`](https://pkg.go.dev/github.com/lmittmann/w3/module/net)
| Method | Go Code
| :------------------- | :-------
| `net_listening` | `net.Listening().Returns(resp *bool)`
| `net_peerCount` | `net.PeerCount().Returns(resp *int)`
| `net_version` | `net.Version().Returns(resp *int)`
### [`web3`](https://pkg.go.dev/github.com/lmittmann/w3/module/web3)
| Method | Go Code
| :------------------- | :-------
| `web3_clientVersion` | `web3.ClientVersion().Returns(clientVersion *string)`
### Third Party RPC Method Packages
| Package | Description
| :----------------------------------------------------------------------- | :-----------
| [github.com/lmittmann/flashbots](https://github.com/lmittmann/flashbots) | Package `flashbots` implements RPC API bindings for the Flashbots relay and mev-geth.
## Custom RPC Method Bindings
Custom RPC method bindings can be created by implementing the [`w3types.RPCCaller`](https://pkg.go.dev/github.com/lmittmann/w3/w3types#RPCCaller) interface.
**Example:** RPC binding for the Otterscan `ots_getTransactionBySenderAndNonce` method ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3types#example-RPCCaller-GetTransactionBySenderAndNonce))
```go
// TxBySenderAndNonceFactory requests the senders transaction hash by the nonce.
func TxBySenderAndNonceFactory(sender common.Address, nonce uint64) w3types.RPCCallerFactory[common.Hash] {
return &getTransactionBySenderAndNonceFactory{
sender: sender,
nonce: nonce,
}
}
// getTransactionBySenderAndNonceFactory implements the w3types.RPCCaller and
// w3types.RPCCallerFactory interfaces. It stores the method parameters and
// the reference to the return value.
type getTransactionBySenderAndNonceFactory struct {
// params
sender common.Address
nonce uint64
// returns
returns *common.Hash
}
// Returns sets the reference to the return value.
func (f *getTransactionBySenderAndNonceFactory) Returns(txHash *common.Hash) w3types.RPCCaller {
f.returns = txHash
return f
}
// CreateRequest creates a batch request element for the Otterscan getTransactionBySenderAndNonce method.
func (f *getTransactionBySenderAndNonceFactory) CreateRequest() (rpc.BatchElem, error) {
return rpc.BatchElem{
Method: "ots_getTransactionBySenderAndNonce",
Args: []any{f.sender, f.nonce},
Result: f.returns,
}, nil
}
// HandleResponse handles the response of the Otterscan getTransactionBySenderAndNonce method.
func (f *getTransactionBySenderAndNonceFactory) HandleResponse(elem rpc.BatchElem) error {
if err := elem.Error; err != nil {
return err
}
return nil
}
```
================================================
FILE: client.go
================================================
/*
Package w3 is your toolbelt for integrating with Ethereum in Go. Closely linked
to [go-ethereum], it provides an ergonomic wrapper for working with RPC, ABI's,
and the EVM.
[go-ethereum]: https://github.com/ethereum/go-ethereum
*/
package w3
import (
"context"
"fmt"
"reflect"
"strings"
"github.com/ethereum/go-ethereum/rpc"
"github.com/lmittmann/w3/w3types"
"golang.org/x/time/rate"
)
// Client represents a connection to an RPC endpoint.
type Client struct {
client *rpc.Client
// rate limiter
rl *rate.Limiter
rlCostFunc func(methods []string) (cost int)
}
// NewClient returns a new Client given an rpc.Client client.
func NewClient(client *rpc.Client, opts ...Option) *Client {
if client == nil {
panic("w3: client is nil")
}
c := &Client{client: client}
for _, opt := range opts {
if opt == nil {
continue
}
opt(c)
}
return c
}
// Dial returns a new Client connected to the URL rawurl. An error is returned
// if the connection establishment fails.
//
// The supported URL schemes are "http", "https", "ws" and "wss". If rawurl is a
// file name with no URL scheme, a local IPC socket connection is established.
func Dial(rawurl string, opts ...Option) (*Client, error) {
client, err := rpc.Dial(rawurl)
if err != nil {
return nil, err
}
return NewClient(client, opts...), nil
}
// MustDial is like [Dial] but panics if the connection establishment fails.
func MustDial(rawurl string, opts ...Option) *Client {
client, err := Dial(rawurl, opts...)
if err != nil {
panic(fmt.Sprintf("w3: %s", err))
}
return client
}
// Close the RPC connection and cancel all in-flight requests.
//
// Close implements the [io.Closer] interface.
func (c *Client) Close() error {
c.client.Close()
return nil
}
// CallCtx creates the final RPC request, sends it, and handles the RPC
// response.
//
// An error is returned if RPC request creation, networking, or RPC response
// handling fails.
func (c *Client) CallCtx(ctx context.Context, calls ...w3types.RPCCaller) error {
// no requests = nothing to do
if len(calls) <= 0 {
return nil
}
// create requests
batchElems := make([]rpc.BatchElem, len(calls))
var err error
for i, req := range calls {
batchElems[i], err = req.CreateRequest()
if err != nil {
return err
}
}
// invoke rate limiter
if err := c.rateLimit(ctx, batchElems); err != nil {
return err
}
// do requests
if len(batchElems) > 1 {
// batch requests if >1 request
err = c.client.BatchCallContext(ctx, batchElems)
if err != nil {
return err
}
} else {
// non-batch requests if 1 request
batchElem := batchElems[0]
err = c.client.CallContext(ctx, batchElem.Result, batchElem.Method, batchElem.Args...)
if err != nil {
switch reflect.TypeOf(err).String() {
case "*rpc.jsonError":
batchElems[0].Error = err
default:
return err
}
}
}
// handle responses
var callErrs CallErrors
for i, req := range calls {
err = req.HandleResponse(batchElems[i])
if err != nil {
if callErrs == nil {
callErrs = make(CallErrors, len(calls))
}
callErrs[i] = err
}
}
if len(callErrs) > 0 {
return callErrs
}
return nil
}
// Call is like [Client.CallCtx] with ctx equal to context.Background().
func (c *Client) Call(calls ...w3types.RPCCaller) error {
return c.CallCtx(context.Background(), calls...)
}
// SubscribeCtx creates a new subscription and returns a [rpc.ClientSubscription].
func (c *Client) SubscribeCtx(ctx context.Context, s w3types.RPCSubscriber) (*rpc.ClientSubscription, error) {
namespace, ch, params, err := s.CreateRequest()
if err != nil {
return nil, err
}
return c.client.Subscribe(ctx, namespace, ch, params...)
}
// Subscribe is like [Client.SubscribeCtx] with ctx equal to context.Background().
func (c *Client) Subscribe(s w3types.RPCSubscriber) (*rpc.ClientSubscription, error) {
return c.SubscribeCtx(context.Background(), s)
}
func (c *Client) rateLimit(ctx context.Context, batchElems []rpc.BatchElem) error {
if c.rl == nil {
return nil
}
if c.rlCostFunc == nil {
// limit requests
return c.rl.Wait(ctx)
}
// limit requests based on Compute Units (CUs)
methods := make([]string, len(batchElems))
for i, batchElem := range batchElems {
methods[i] = batchElem.Method
}
cost := c.rlCostFunc(methods)
return c.rl.WaitN(ctx, cost)
}
// CallErrors is an error type that contains the errors of multiple calls. The
// length of the error slice is equal to the number of calls. Each error at a
// given index corresponds to the call at the same index. An error is nil if the
// corresponding call was successful.
type CallErrors []error
func (e CallErrors) Error() string {
if len(e) == 1 && e[0] != nil {
return fmt.Sprintf("w3: call failed: %s", e[0])
}
var errors []string
for i, err := range e {
if err == nil {
continue
}
errors = append(errors, fmt.Sprintf("call[%d]: %s", i, err))
}
var plr string
if len(errors) > 1 {
plr = "s"
}
return fmt.Sprintf("w3: %d call%s failed:\n%s", len(errors), plr, strings.Join(errors, "\n"))
}
func (e CallErrors) Is(target error) bool {
_, ok := target.(CallErrors)
return ok
}
// An Option configures a Client.
type Option func(*Client)
// WithRateLimiter sets the rate limiter for the client. Set the optional argument
// costFunc to nil to limit the number of requests. Supply a costFunc to limit
// the number of requests based on individual RPC calls for advanced rate
// limiting by e.g. Compute Units (CUs). Note that only if len(methods) > 1, the
// calls are sent in a batch request.
func WithRateLimiter(rl *rate.Limiter, costFunc func(methods []string) (cost int)) Option {
return func(c *Client) {
c.rl = rl
c.rlCostFunc = costFunc
}
}
================================================
FILE: client_test.go
================================================
package w3_test
import (
"bytes"
"context"
"errors"
"flag"
"math/big"
"strconv"
"testing"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rpc"
"github.com/google/go-cmp/cmp"
"github.com/lmittmann/w3"
"github.com/lmittmann/w3/internal"
"github.com/lmittmann/w3/module/eth"
"github.com/lmittmann/w3/rpctest"
"github.com/lmittmann/w3/w3types"
)
var (
benchRPC = flag.String("benchRPC", "", "RPC endpoint for benchmark")
jsonCalls1 = `> {"jsonrpc":"2.0","id":1}` + "\n" +
`< {"jsonrpc":"2.0","id":1,"result":"0x1"}`
jsonCalls2 = `> [{"jsonrpc":"2.0","id":1},{"jsonrpc":"2.0","id":2}]` + "\n" +
`< [{"jsonrpc":"2.0","id":1,"result":"0x1"},{"jsonrpc":"2.0","id":2,"result":"0x1"}]`
)
func TestClientCall(t *testing.T) {
tests := []struct {
Buf *bytes.Buffer
Calls []w3types.RPCCaller
WantErr error
}{
{
Buf: bytes.NewBufferString(jsonCalls1),
Calls: []w3types.RPCCaller{&testCaller{}},
},
{
Buf: bytes.NewBufferString(jsonCalls1),
Calls: []w3types.RPCCaller{&testCaller{RequestErr: errors.New("err")}},
WantErr: errors.New("err"),
},
{
Buf: bytes.NewBufferString(jsonCalls1),
Calls: []w3types.RPCCaller{&testCaller{ReturnErr: errors.New("err")}},
WantErr: errors.New("w3: call failed: err"),
},
{
Buf: bytes.NewBufferString(jsonCalls2),
Calls: []w3types.RPCCaller{
&testCaller{RequestErr: errors.New("err")},
&testCaller{},
},
WantErr: errors.New("err"),
},
{
Buf: bytes.NewBufferString(jsonCalls2),
Calls: []w3types.RPCCaller{
&testCaller{ReturnErr: errors.New("err")},
&testCaller{},
},
WantErr: errors.New("w3: 1 call failed:\ncall[0]: err"),
},
{
Buf: bytes.NewBufferString(jsonCalls2),
Calls: []w3types.RPCCaller{
&testCaller{},
&testCaller{ReturnErr: errors.New("err")},
},
WantErr: errors.New("w3: 1 call failed:\ncall[1]: err"),
},
{
Buf: bytes.NewBufferString(jsonCalls2),
Calls: []w3types.RPCCaller{
&testCaller{ReturnErr: errors.New("err")},
&testCaller{ReturnErr: errors.New("err")},
},
WantErr: errors.New("w3: 2 calls failed:\ncall[0]: err\ncall[1]: err"),
},
}
for i, test := range tests {
t.Run(strconv.Itoa(i), func(t *testing.T) {
srv := rpctest.NewServer(t, test.Buf)
client, err := w3.Dial(srv.URL())
if err != nil {
t.Fatalf("Failed to connect to test RPC endpoint: %v", err)
}
err = client.Call(test.Calls...)
if diff := cmp.Diff(test.WantErr, err,
internal.EquateErrors(),
); diff != "" {
t.Fatalf("(-want, +got)\n%s", diff)
}
})
}
}
func TestClientCall_CallErrors(t *testing.T) {
srv := rpctest.NewServer(t, bytes.NewBufferString(jsonCalls2))
client, err := w3.Dial(srv.URL())
if err != nil {
t.Fatalf("Failed to connect to test RPC endpoint: %v", err)
}
err = client.Call(&testCaller{}, &testCaller{ReturnErr: errors.New("err")})
if err == nil {
t.Fatal("Want error")
}
if !errors.Is(err, w3.CallErrors{}) {
t.Fatalf("Want w3.CallErrors, got %T", err)
}
callErrs := err.(w3.CallErrors)
if callErrs[0] != nil {
t.Errorf("callErrs[0]: want <nil>, got %v", callErrs[0])
}
if callErrs[1] == nil || callErrs[1].Error() != "err" {
t.Errorf(`callErrs[1]: want "err", got %v`, callErrs[1])
}
}
type testCaller struct {
RequestErr error
ReturnErr error
}
func (c *testCaller) CreateRequest() (elem rpc.BatchElem, err error) {
return rpc.BatchElem{}, c.RequestErr
}
func (c *testCaller) HandleResponse(elem rpc.BatchElem) (err error) {
return c.ReturnErr
}
func BenchmarkCall_BalanceNonce(b *testing.B) {
if *benchRPC == "" {
b.Skipf("Missing -benchRPC")
}
w3Client := w3.MustDial(*benchRPC)
defer w3Client.Close()
ethClient, _ := ethclient.Dial(*benchRPC)
defer ethClient.Close()
addr := common.Address{}
b.Run("Batch", func(b *testing.B) {
var (
nonce uint64
balance *big.Int
)
for range b.N {
w3Client.Call(
eth.Nonce(addr, nil).Returns(&nonce),
eth.Balance(addr, nil).Returns(&balance),
)
}
})
b.Run("Sequential", func(b *testing.B) {
for range b.N {
ethClient.NonceAt(context.Background(), addr, nil)
ethClient.BalanceAt(context.Background(), addr, nil)
}
})
}
func BenchmarkCall_Balance100(b *testing.B) {
if *benchRPC == "" {
b.Skipf("Missing -benchRPC")
}
w3Client := w3.MustDial(*benchRPC)
defer w3Client.Close()
ethClient, _ := ethclient.Dial(*benchRPC)
defer ethClient.Close()
addr100 := make([]common.Address, 100)
for i := range len(addr100) {
addr100[i] = common.BigToAddress(big.NewInt(int64(i)))
}
b.Run("Batch", func(b *testing.B) {
var balance *big.Int
for range b.N {
requests := make([]w3types.RPCCaller, len(addr100))
for j := range len(requests) {
requests[j] = eth.Balance(addr100[j], nil).Returns(&balance)
}
w3Client.Call(requests...)
}
})
b.Run("Sequential", func(b *testing.B) {
for range b.N {
for _, addr := range addr100 {
ethClient.BalanceAt(context.Background(), addr, nil)
}
}
})
}
func BenchmarkCall_BalanceOf100(b *testing.B) {
if *benchRPC == "" {
b.Skipf("Missing -benchRPC")
}
w3Client := w3.MustDial(*benchRPC)
defer w3Client.Close()
ethClient, _ := ethclient.Dial(*benchRPC)
defer ethClient.Close()
addr100 := make([]common.Address, 100)
for i := range len(addr100) {
addr100[i] = common.BigToAddress(big.NewInt(int64(i)))
}
funcBalanceOf := w3.MustNewFunc("balanceOf(address)", "uint256")
addrWeth9 := w3.A("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2")
b.Run("Batch", func(b *testing.B) {
var balance big.Int
for range b.N {
requests := make([]w3types.RPCCaller, len(addr100))
for j := range len(requests) {
requests[j] = eth.CallFunc(addrWeth9, funcBalanceOf, addr100[j]).Returns(&balance)
}
w3Client.Call(requests...)
}
})
b.Run("Sequential", func(b *testing.B) {
for range b.N {
for _, addr := range addr100 {
input, err := funcBalanceOf.EncodeArgs(addr)
if err != nil {
b.Fatalf("Failed to encode args: %v", err)
}
ethClient.CallContract(context.Background(), ethereum.CallMsg{
To: &addrWeth9,
Data: input,
}, nil)
}
}
})
}
func BenchmarkCall_Block100(b *testing.B) {
if *benchRPC == "" {
b.Skipf("Missing -benchRPC")
}
w3Client := w3.MustDial(*benchRPC)
defer w3Client.Close()
ethClient, _ := ethclient.Dial(*benchRPC)
defer ethClient.Close()
block100 := make([]*big.Int, 100)
for i := range len(block100) {
block100[i] = big.NewInt(int64(14_000_000 + i))
}
b.Run("Batch", func(b *testing.B) {
var block *types.Block
for range b.N {
requests := make([]w3types.RPCCaller, len(block100))
for j := range len(requests) {
requests[j] = eth.BlockByNumber(block100[j]).Returns(&block)
}
w3Client.Call(requests...)
}
})
b.Run("Sequential", func(b *testing.B) {
for range b.N {
for _, number := range block100 {
ethClient.BlockByNumber(context.Background(), number)
}
}
})
}
================================================
FILE: docs/components/DocLink.jsx
================================================
import { Link } from 'nextra-theme-docs'
import { Code } from 'nextra/components'
const pkgNameToPath = {
'w3': 'github.com/lmittmann/w3',
'module': 'github.com/lmittmann/w3/module',
'debug': 'github.com/lmittmann/w3/module/debug',
'eth': 'github.com/lmittmann/w3/module/eth',
'txpool': 'github.com/lmittmann/w3/module/txpool',
'web3': 'github.com/lmittmann/w3/module/web3',
'w3types': 'github.com/lmittmann/w3/w3types',
'w3vm': 'github.com/lmittmann/w3/w3vm',
'hooks': 'github.com/lmittmann/w3/w3vm/hooks',
'tracing': 'github.com/ethereum/go-ethereum/core/tracing',
'logger': 'github.com/ethereum/go-ethereum/eth/tracers/logger',
}
export const DocLink = ({ title, id }) => {
if (typeof id === 'undefined') { id = title }
let dotIndex = id.indexOf('.');
let pkg = id.substring(0, dotIndex);
let comp = id.substring(dotIndex + 1);
return (
<Link href={`https://pkg.go.dev/${pkgNameToPath[pkg]}#${comp}`}>
<Code>{title}</Code>
</Link>
)
}
================================================
FILE: docs/next.config.js
================================================
import nextra from 'nextra'
const withNextra = nextra({
theme: 'nextra-theme-docs',
themeConfig: './theme.config.jsx',
staticImage: true,
search: {
codeblocks: true
},
defaultShowCopyCode: true
})
export default withNextra({
output: 'export',
reactStrictMode: true,
images: {
unoptimized: true,
}
})
================================================
FILE: docs/package.json
================================================
{
"type": "module",
"scripts": {
"dev": "next dev",
"build": "next build"
},
"dependencies": {
"next": "^14.2.14",
"nextra": "3.0.0-alpha.40",
"nextra-theme-docs": "3.0.0-alpha.40",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"autoprefixer": "^10.4.20",
"postcss": "^8.4.47",
"tailwindcss": "^3.4.13"
}
}
================================================
FILE: docs/pages/404.mdx
================================================
# Page Not Found
Get back on track: [Homepage](/)
================================================
FILE: docs/pages/_app.js
================================================
import './style.css'
import 'nextra-theme-docs/style.css'
import { Inter } from 'next/font/google'
const inter = Inter({ subsets: ['latin'] })
export default function Nextra({ Component, pageProps }) {
const getLayout = Component.getLayout || ((page) => page)
return getLayout(
<div className={inter.className}>
<Component {...pageProps} />
</div>
)
}
================================================
FILE: docs/pages/_meta.js
================================================
export default {
index: {
title: 'Overview',
display: 'hidden',
theme: { breadcrumb: false, toc: false, pagination: false },
},
'404': {
title: '404',
display: 'hidden',
theme: {
breadcrumb: false,
toc: false,
layout: 'full',
pagination: false,
}
},
'--- RPC Client': {
type: 'separator',
title: 'RPC Client'
},
'rpc-overview': {
title: 'Overview',
theme: { breadcrumb: false },
},
'rpc-methods': {
title: 'Methods',
theme: { breadcrumb: false },
},
'rpc-extension': {
title: 'Extension',
theme: { breadcrumb: false },
},
'+++ VM': {
'title': '',
'type': 'separator'
},
'--- VM': {
type: 'separator',
title: 'VM'
},
'vm-overview': {
title: 'Overview',
theme: { breadcrumb: false },
},
'vm-tracing': {
title: 'Tracing',
theme: { breadcrumb: false },
},
'vm-testing': {
title: 'Testing',
theme: { breadcrumb: false },
},
'+++ HELPER': {
'title': '',
'type': 'separator'
},
'--- HELPER': {
type: 'separator',
title: 'Helper'
},
'helper-abi': {
title: 'ABI',
theme: { breadcrumb: false },
},
'helper-utils': {
title: 'Utils',
theme: { breadcrumb: false },
},
examples: {
title: 'Examples',
type: 'page',
},
releases: {
title: 'Releases',
type: 'page',
href: 'https://github.com/lmittmann/w3/releases',
newWindow: true
},
godoc: {
title: 'GoDoc',
type: 'page',
href: 'https://pkg.go.dev/github.com/lmittmann/w3#section-documentation',
newWindow: true
},
}
================================================
FILE: docs/pages/examples/_meta.js
================================================
export default {
index: {
title: 'Examples',
display: 'hidden',
theme: { breadcrumb: false, toc: true, pagination: false },
},
}
================================================
FILE: docs/pages/examples/index.mdx
================================================
# Examples
## `w3.Client` Examples
* **Batch Fetch** 1000 blocks ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-BatchBlocks))
* **Batch Call** the name, symbol, decimals, and balanceOf functions of the Wrapped Ether in a single batch ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-BatchCallFunc))
* **Batch Call** the Uniswap V3 Quoter for quotes on swapping 100 WETH for DAI in pools of all fee tiers in a single batch ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-BatchCallFuncUniswapQuoter))
* **Batch Fetch** the nonce and balance of an EOA in a single batch ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-BatchEOAState))
* **Batch Fetch** a transaction and its receipt in a single batch ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-BatchTxDetails))
* **Call** the token balance of an address ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-CallFunc))
* **Call** the token balance of an address, with state override ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-CallFuncWithStateOverride))
* **Handle errors** of individual calls in a batch ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-BatchHandleError))
* **Rate Limit** the number of requests to 300 compute units (CUs) per second, with bursts of up to 300 CUs. An individual CU can be charged per RPC method call ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-RateLimitByComputeUnits))
* **Rate Limit** the number of requests to 10 per second, with bursts of up to 20 requests ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-RateLimitByRequest))
* **Send Ether** transfer ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-SendETHTransfer))
* **Send ERC20 token** transfer (Wrapped Ether) ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-SendTokenTransfer))
* **Subscribe** to pending transactions ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client-SubscribeToPendingTransactions))
**[See all examples ↗](https://pkg.go.dev/github.com/lmittmann/w3#pkg-examples)**
## `w3vm.VM` Examples
* **Ether transfer** ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-SimpleTransfer))
* **ERC20 token transfer** with faked token balance (Wrapped Ether) ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-FakeTokenBalance))
* **Uniswap V3 swap** ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-UniswapV3Swap))
* **Call ERC20 balanceOf** with raw a `w3types.Message` using the `Message.{Func,Args}` helper ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-Call))
* **Call ERC20 balanceOf**, using the `VM.CallFunc` helper ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-CallFunc))
* **Prank** a sender ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-PrankZeroAddress))
* **Trace calls** (and opcodes) of a transaction ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-TraceCalls))
* **Trace** the execution to obtain the access list ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-TraceAccessList))
* **Trace** the execution of all op's in a block ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-TraceBlock))
**[See all examples ↗](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#pkg-examples)**
================================================
FILE: docs/pages/examples.mdx
================================================
================================================
FILE: docs/pages/helper-abi.mdx
================================================
# ABI Bindings
ABI bindings allow the encoding and decoding of Smart Contract function calls or the decoding of events.
In `w3` ABI bindings are defined for individual functions or events at runtime using Solidity syntax.
* **Easy to write:** Creating an ABI binding only requires the Solidity function signature. No need
to firstly generate an ABI json file using `solc` and secondly generate ABI bindings using `abigen`.
* **Flexible:** ABI bindings for a function or event can be used with any Smart Contract. No need to
generate overlapping bindings for multiple Smart Contracts.
## Functions
Function ABI bindings can be defined using
* `func NewFunc(signature, returns string) (*Func, error)`, or
* `func MustNewFunc(signature, returns string) *Func` which panics on error.
### Syntax
Function signatures are defined using Solidity syntax. Arguments and returns can optionally be named. While naming is optional, it is recommended for more complex functions or tuple variables. Alias types, such as `uint` for `uint256`, are supported.
#### Example: ERC20 `balanceOf`
ABI binding for the ERC20 `balanceOf` function ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-NewFunc-BalanceOf)):
```solidity filename="Solidity"
interface IERC20 {
function balanceOf(address account) external view returns (uint256);
// ...
}
```
```go filename="Go"
var funcBalanceOf = w3.MustNewFunc("balanceOf(address)", "uint256")
// or
var funcBalanceOf = w3.MustNewFunc("balanceOf(address who)", "uint256 amount")
```
#### Example: QuoterV2 `quoteExactInputSingle`
ABI binding for the Uniswap QuoterV2 `quoteExactInputSingle` function with a tuple parameter (Solidity `struct`):
```solidity filename="Solidity"
interface QuoterV2 {
struct QuoteExactInputSingleParams {
address tokenIn;
address tokenOut;
uint256 amountIn;
uint24 fee;
uint160 sqrtPriceLimitX96;
}
function quoteExactInputSingle(QuoteExactInputSingleParams memory params)
external
returns (
uint256 amountOut,
uint160 sqrtPriceX96After,
uint32 initializedTicksCrossed,
uint256 gasEstimate
);
// ...
}
```
```go filename="Go"
type QuoteExactInputSingleParams struct {
TokenIn common.Address
TokenOut common.Address
AmountIn *big.Int
Fee *big.Int `abitype:"uint24"`
SqrtPriceLimitX96 *big.Int `abitype:"uint160"`
}
var funcQuoteExactInputSingle = w3.MustNewFunc(
`quoteExactInputSingle(QuoteExactInputSingleParams params)`,
`uint256 amountOut,
uint160 sqrtPriceX96After,
uint32 initializedTicksCrossed,
uint256 gasEstimate`,
QuoteExactInputSingleParams{}, // Pass struct type as tuple definition
)
```
##### Alternative: Inline Tuple Definition
For simple cases or when you prefer not to define separate structs, you can use inline tuple definitions:
```go filename="Go"
var funcQuoteExactInputSingle = w3.MustNewFunc(
`quoteExactInputSingle((
address tokenIn,
address tokenOut,
uint256 amountIn,
uint24 fee,
uint160 sqrtPriceLimitX96
) params)`,
`uint256 amountOut,
uint160 sqrtPriceX96After,
uint32 initializedTicksCrossed,
uint256 gasEstimate`,
)
```
### Tuples (Solidity `struct`'s)
Tuple types need to be embedded in parentheses, with comma-separated fields. Fields must be named, so they can be mapped to the fields of a Go struct.
To map a tuple type to a Go struct, the struct must be defined manually with each tuple field being mapped to a Go struct field. Field names need to match, but Go field names must always start with an uppercase letter. E.g. the tuple field `address tokenIn{:solidity}` must be matched to the Go struct field `TokenIn common.Address{:go}`.
<Callout type="info">
See [Type Mappings](#type-mappings) for more information on how to map primitive Solidity types to Go types and vice versa.
</Callout>
### `EncodeArgs`
The `EncodeArgs` method of a `Func` ABI encodes a Solidity function call. Each argument of the Solidity function must be matched by a corresponding Go value.
### `DecodeArgs` and `DecodeReturns`
The `DecodeArgs` and `DecodeReturns` methods of a `Func` ABI decode the arguments and returns of a Solidity function call. The Go values that should hold the decoded data must be defined beforehand, and passed as pointers to the decode methods. Values that should not be decoded can be passed as `nil`. Tailing `nil` values can be omitted.
#### Example: Uniswap Pair `getReserves`
ABI decode the output of the Uniswap Pair `getReserves` function ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Func.DecodeReturns-GetReserves)):
```go filename="Go"
var (
funcGetReserves = w3.MustNewFunc("getReserves()", "uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast")
output []byte = w3.B("0x00…")
)
var (
reserve0, reserve1 *big.Int
blockTimestampLast uint32
)
if err := funcGetReserves.DecodeReturns(output, &reserve0, &reserve1, &blockTimestampLast); err != nil {
// ...
}
```
In case only the reserves should be decoded, the `blockTimestampLast` can be ignored using `funcGetReserves.DecodeReturns(output, &reserve0, &reserve1, nil){:go}`, which is equivalent to `funcGetReserves.DecodeReturns(output, &reserve0, &reserve1){:go}`.
## Events
Event ABI bindings can be defined using
* `func NewEvent(signature string) (*Event, error)`, or
* `func MustNewEvent(signature string) *Event` which panics on error.
#### Example: ERC20 `Transfer`
ABI binding for the ERC20 `Transfer` event:
```solidity filename="Solidity"
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
// ...
}
```
```go filename="Go"
var evtTransfer = w3.MustNewEvent("Transfer(address indexed from, address indexed to, uint256 value)")
```
## Type Mappings
| **Solidity Type** | **Go Type** |
|:-----------------------------------------------------|:----------------------------|
| `bool` | `bool` |
| `int8` | `int8` |
| `int16` | `int16` |
| `int32` | `int32` |
| `int64` | `int64` |
| `int24`,`int40`…`int56`,`int72`…`int256`,`int` | `*big.Int` |
| `uint8` | `uint8` |
| `uint16` | `uint16` |
| `uint32` | `uint32` |
| `uint64` | `uint64` |
| `uint24`,`uint40`…`uint56`,`uint72`…`uint256`,`uint` | `*big.Int` |
| `bytes` | `[]byte` |
| `bytes1`…`bytes32` | `[1]byte`…`[32]byte` |
| `address` | `common.Address`/`[20]byte` |
| `bytes32` | `common.Hash`/`[32]byte` |
### Arrays and Slices
Solidity arrays and slices are mapped to Go arrays and slices respectively and vice versa.
| **Solidity Type** | **Go Type** |
|:------------------|:------------|
| `type[n]` | `[n]type` |
| `type[]` | `[]type` |
================================================
FILE: docs/pages/helper-utils.mdx
================================================
# Utils
Static addresses, hashes, bytes or integers can be parsed from (hex-)strings with the following utility functions that panic if the string is not valid.
```go
addr := w3.A("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
hash := w3.H("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3")
bytes := w3.B("0x27c5342c")
amount := w3.I("12.34 ether")
```
Use [go-ethereum/common](https://pkg.go.dev/github.com/ethereum/go-ethereum/common) to parse strings that may not be valid instead.
================================================
FILE: docs/pages/index.mdx
================================================
---
description: 'w3: Enhanced Ethereum Integration for Go'
---
# `w3`: Enhanced Ethereum Integration for Go
<div className="flex flex-wrap gap-2 my-2">
<a href="https://pkg.go.dev/github.com/lmittmann/w3">
<img src="https://pkg.go.dev/badge/github.com/lmittmann/w3.svg" alt="Go Reference" />
</a>
<a href="https://goreportcard.com/report/github.com/lmittmann/w3">
<img src="https://goreportcard.com/badge/github.com/lmittmann/w3" alt="Go Report Card" />
</a>
<a href="https://coveralls.io/github/lmittmann/w3?branch=main">
<img src="https://coveralls.io/repos/github/lmittmann/w3/badge.svg?branch=main" alt="Coverage Status" />
</a>
<a href="https://github.com/lmittmann/w3/releases">
<img src="https://img.shields.io/github/v/release/lmittmann/w3" alt="Latest Release" />
</a>
<a href="https://t.me/w3_golang">
<img src="https://img.shields.io/badge/Telegram-blue?logo=telegram&logoColor=white" alt="Chat on Telegram" />
</a>
</div>
<Image src="/gopher.png" alt="W3 Gopher" width={158} height={224} align="right" className="ml-2 md:ml-6 mb-2"/>
`w3` is your toolbelt for integrating with Ethereum in Go. Closely linked to `go‑ethereum`, it provides an ergonomic wrapper for working with **RPC**, **ABI's**, and the **EVM**.
```txt
go get github.com/lmittmann/w3
```
## At a Glance
* Use `w3.Client` to connect to an RPC endpoint. The client features batch request support for up to **80x faster requests** and easy extendibility. [learn more ➔](/rpc-overview)
* Use `w3vm.VM` to simulate EVM execution with optional tracing and Mainnet state forking, or test Smart Contracts. [learn more ➔](/vm-overview)
* Use `w3.Func` and `w3.Event` to create ABI bindings from Solidity function and event signatures. [learn more ➔](/helper-abi)
* Use `w3.A`, `w3.H`, and many other utility functions to parse addresses, hashes, and other common types from strings. [learn more ➔](/helper-utils)
## Sponsors
<div class="mt-4">
<img src="/assets/ef-logo.svg" alt="EF Logo" class="w-full max-w-72 dark:hidden" />
<img src="/assets/ef-logo-dark.svg" alt="EF Logo Dark" class="w-full max-w-72 hidden dark:block" />
</div>
================================================
FILE: docs/pages/rpc-extension.mdx
================================================
# Custom RPC Method Bindings
Custom RPC method bindings can be created by implementing the <DocLink title="w3types.RPCCaller" /> interface. By convention, the `w3types.RPCCaller` is setup using an unexported factory, which implements the <DocLink title="w3types.RPCCallerFactory" /> interface, to keep the package API small and readable. The factory stores the method parameters and the reference to the return value.
**Example:** RPC binding for the Otterscan `ots_getTransactionBySenderAndNonce` method ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3types#example-RPCCaller-GetTransactionBySenderAndNonce))
```go
// TxBySenderAndNonceFactory requests the senders transaction hash by the nonce.
func TxBySenderAndNonceFactory(sender common.Address, nonce uint64) w3types.RPCCallerFactory[common.Hash] {
return &getTransactionBySenderAndNonceFactory{
sender: sender,
nonce: nonce,
}
}
// getTransactionBySenderAndNonceFactory implements the w3types.RPCCaller and
// w3types.RPCCallerFactory interfaces. It stores the method parameters and
// the reference to the return value.
type getTransactionBySenderAndNonceFactory struct {
// params
sender common.Address
nonce uint64
// returns
returns *common.Hash
}
// Returns sets the reference to the return value.
func (f *getTransactionBySenderAndNonceFactory) Returns(txHash *common.Hash) w3types.RPCCaller {
f.returns = txHash
return f
}
// CreateRequest creates a batch request element for the Otterscan getTransactionBySenderAndNonce method.
func (f *getTransactionBySenderAndNonceFactory) CreateRequest() (rpc.BatchElem, error) {
return rpc.BatchElem{
Method: "ots_getTransactionBySenderAndNonce",
Args: []any{f.sender, f.nonce},
Result: f.returns,
}, nil
}
// HandleResponse handles the response of the Otterscan getTransactionBySenderAndNonce method.
func (f *getTransactionBySenderAndNonceFactory) HandleResponse(elem rpc.BatchElem) error {
if err := elem.Error; err != nil {
return err
}
return nil
}
```
================================================
FILE: docs/pages/rpc-methods/_meta.js
================================================
export default {
eth: 'eth',
debug: 'debug',
txpool: 'txpool',
admin: 'admin',
net: 'net',
web3: 'web3',
}
================================================
FILE: docs/pages/rpc-methods/admin.mdx
================================================
# `admin`-Namespace
List of supported RPC methods for `w3.Client` in the `admin`-namespace.
## `admin_addPeer`
`AddPeer` adds a new peer to the node's peer set and returns a bool indicating success.
```go {3}
var success bool
client.Call(
admin.AddPeer(url).Returns(&success),
)
```
## `admin_removePeer`
`RemovePeer` removes a peer from the node's peer set and returns a bool indicating success.
```go {3}
var success bool
client.Call(
admin.RemovePeer(url).Returns(&success),
)
```
## `admin_addTrustedPeer`
`AddTrustedPeer` adds a new trusted peer to the node's trusted peer set and returns a bool indicating success.
```go {3}
var success bool
client.Call(
admin.AddTrustedPeer(url).Returns(&success),
)
```
## `admin_removeTrustedPeer`
`RemoveTrustedPeer` removes a trusted peer from the node's trusted peer set and returns a bool indicating success.
```go {3}
var success bool
client.Call(
admin.RemoveTrustedPeer(url).Returns(&success),
)
```
## `admin_nodeInfo`
`NodeInfo` returns information about the running node.
```go {3}
var nodeInfo *admin.NodeInfoResponse
client.Call(
admin.NodeInfo().Returns(&nodeInfo),
)
```
================================================
FILE: docs/pages/rpc-methods/debug.mdx
================================================
# `debug`-Namespace
List of supported RPC methods for `w3.Client` in the `debug`-namespace.
## `debug_traceCall`
`TraceCall` requests the trace of the given message.
```go {3}
var trace *debug.Trace
client.Call(
debug.TraceCall(msg, blockNumber, config).Returns(&trace),
)
```
`CallTraceCall` requests the call trace of the given message.
```go {3}
var trace *debug.CallTrace
client.Call(
debug.CallTraceCall(msg, blockNumber, overrides).Returns(&trace),
)
```
## `debug_traceTransaction`
`TraceTx` requests the trace of the transaction with the given hash.
TraceTx requests the trace of the transaction with the given hash.
```go {3}
var trace *debug.Trace
client.Call(
debug.TraceTx(txHash, config).Returns(&trace),
)
```
`CallTraceTx` requests the call trace of the transaction with the given hash.
```go {3}
var trace *debug.CallTrace
client.Call(
debug.CallTraceTx(txHash, overrides).Returns(&trace),
)
```
================================================
FILE: docs/pages/rpc-methods/eth.mdx
================================================
# `eth`-Namespace
List of supported RPC methods for `w3.Client` in the `eth`-namespace.
## `eth_blockNumber`
`BlockNumber` requests the number of the most recent block.
```go {3}
var blockNumber *big.Int
client.Call(
eth.BlockNumber().Returns(&blockNumber),
)
```
## `eth_call`
`Call` requests the output data of the given message at the given blockNumber. If blockNumber is nil, the output of the message at the latest known block is requested.
```go {3}
var output []byte
client.Call(
eth.Call(msg, blockNumber, overrides).Returns(&output),
)
```
## `eth_chainId`
`ChainID` requests the chains ID.
```go {3}
var chainID uint64
client.Call(
eth.ChainID().Returns(&chainID),
)
```
## `eth_createAccessList`
`AccessList` requests the access list of the given message at the given blockNumber. If blockNumber is nil, the access list of the message at the latest block is requested.
```go {3}
var accessListResp *AccessListResponse
client.Call(
eth.AccessList(msg, blockNumber).Returns(&accessListResp),
)
```
## `eth_estimateGas`
`EstimateGas` requests the estimated gas cost of the given message at the given blockNumber. If blockNumber is nil, the estimated gas cost of the message at the latest block is requested.
```go {3}
var gas uint64
client.Call(
eth.EstimateGas(msg, blockNumber).Returns(&gas),
)
```
## `eth_gasPrice`
`GasPrice` requests the current gas price in wei.
```go {3}
var gasPrice *big.Int
client.Call(
eth.GasPrice().Returns(&gasPrice),
)
```
## `eth_maxPriorityFeePerGas`
`GasTipCap` requests the currently suggested gas tip cap after EIP-1559 to allow a timely execution of a transaction.
```go {3}
var gasTipCap *big.Int
client.Call(
eth.GasTipCap().Returns(&gasTipCap),
)
```
## `eth_getBalance`
`Balance` requests the balance of the given common.Address addr at the given blockNumber. If blockNumber is nil, the balance at the latest known block is requested.
```go {3}
var balance *big.Int
client.Call(
eth.Balance(addr, blockNumber).Returns(&balance),
)
```
## `eth_getBlockByHash`
`BlockByHash` requests the block with the given hash with full transactions.
```go {3}
var block *types.Block
client.Call(
eth.BlockByHash(hash).Returns(&block),
)
```
## `eth_getBlockByNumber`
`BlockByNumber` requests the block with the given number with full transactions. If number is nil, the latest block is requested.
```go {3}
var block *types.Block
client.Call(
eth.BlockByNumber(number).Returns(&block),
)
```
## `eth_getBlockReceipts`
`BlockReceipts` requests all receipts of the transactions in the given block.
```go {3}
var receipts types.Receipts
client.Call(
eth.BlockReceipts(blockNumber).Returns(&receipts),
)
```
## `eth_getBlockTransactionCountByHash`
`BlockTxCountByHash` requests the number of transactions in the block with the given hash.
```go {3}
var count uint
client.Call(
eth.BlockTxCountByHash(hash).Returns(&count),
)
```
## `eth_getBlockTransactionCountByNumber`
`BlockTxCountByNumber` requests the number of transactions in the block with the given number.
```go {3}
var count uint
client.Call(
eth.BlockTxCountByNumber(number).Returns(&count),
)
```
## `eth_getCode`
`Code` requests the code of the given common.Address addr at the given blockNumber. If blockNumber is nil, the code at the latest known block is requested.
```go {3}
var code []byte
client.Call(
eth.Code(addr, blockNumber).Returns(&code),
)
```
## `eth_getLogs`
`Logs` requests the logs of the given ethereum.FilterQuery q.
```go {3}
var logs []types.Log
client.Call(
eth.Logs(query).Returns(&logs),
)
```
## `eth_getStorageAt`
`StorageAt` requests the storage of the given common.Address addr at the given common.Hash slot at the given blockNumber. If block number is nil, the slot at the latest known block is requested.
```go {3}
var storage common.Hash
client.Call(
eth.StorageAt(addr, slot, blockNumber).Returns(&storage),
)
```
## `eth_getTransactionByHash`
`Tx` requests the transaction with the given hash.
```go {3}
var tx *types.Transaction
client.Call(
eth.Tx(hash).Returns(&tx),
)
```
## `eth_getTransactionByBlockHashAndIndex`
`TxByBlockHashAndIndex` requests the transaction in the given block with the given index.
```go {3}
var tx *types.Transaction
client.Call(
eth.TxByBlockHashAndIndex(blockHash, index).Returns(&tx),
)
```
## `eth_getTransactionByBlockNumberAndIndex`
`TxByBlockNumberAndIndex` requests the transaction in the given block with the given index.
```go {3}
var tx *types.Transaction
client.Call(
eth.TxByBlockNumberAndIndex(blockNumber, index).Returns(&tx),
)
```
## `eth_getTransactionCount`
`Nonce` requests the nonce of the given common.Address addr at the given blockNumber. If blockNumber is nil, the nonce at the latest known block is requested.
```go {3}
var count uint
client.Call(
eth.Nonce(addr, blockHash).Returns(&count),
)
```
## `eth_getTransactionReceipt`
`TxReceipt` requests the receipt of the transaction with the given hash.
```go {3}
var receipt *types.Receipt
client.Call(
eth.TxReceipt(txHash).Returns(&receipt),
)
```
## `eth_sendRawTransaction`
`SendRawTx` sends a raw transaction to the network and returns its hash.
```go {3}
var txHash common.Hash
client.Call(
eth.SendRawTx(rawTx).Returns(&txHash),
)
```
SendTx sends a signed transaction to the network and returns its hash.
```go {3}
var txHash common.Hash
client.Call(
eth.SendTx(tx).Returns(&txHash),
)
```
## `eth_getUncleByBlockHashAndIndex`
`UncleByBlockHashAndIndex` requests the uncle of the block with the given hash at the given index.
```go {3}
var uncle *types.Header
client.Call(
eth.UncleByBlockHashAndIndex(hash, index).Returns(&uncle),
)
```
## `eth_getUncleByBlockNumberAndIndex`
`UncleByBlockNumberAndIndex` requests the uncle of the block with the given number at the given index.
```go {3}
var uncle *types.Header
client.Call(
eth.UncleByBlockNumberAndIndex(number, index).Returns(&uncle),
)
```
## `eth_getUncleCountByBlockHash`
`UncleCountByBlockHash` requests the number of uncles of the block with the given hash.
```go {3}
var count uint
client.Call(
eth.UncleCountByBlockHash(hash).Returns(&count),
)
```
## `eth_getUncleCountByBlockNumber`
`UncleCountByBlockNumber` requests the number of uncles of the block with the given number.
```go {3}
var count uint
client.Call(
eth.UncleCountByBlockNumber(number).Returns(&count),
)
```
## `eth_syncing`
`Syncing` requests the syncing status of the node.
```go {3}
var syncing bool
client.Call(
eth.Syncing().Returns(&syncing),
)
```
================================================
FILE: docs/pages/rpc-methods/net.mdx
================================================
# `net`-Namespace
List of supported RPC methods for `w3.Client` in the `net`-namespace.
## `net_listening`
`Listening` returns whether the client is actively listening for network connections.
```go {3}
var listening bool
client.Call(
net.Listening().Returns(&listening),
)
```
## `net_peerCount`
`PeerCount` returns the number of peers connected to the node.
```go {3}
var peerCount int
client.Call(
net.PeerCount().Returns(&peerCount),
)
```
## `net_version`
`Version` returns the network ID (e.g. 1 for mainnet).
```go {3}
var version int
client.Call(
net.Version().Returns(&version),
)
```
================================================
FILE: docs/pages/rpc-methods/txpool.mdx
================================================
# `txpool`-Namespace
List of supported RPC methods for `w3.Client` in the `txpool`-namespace.
## `txpool_content`
`Content` requests the pending and queued transactions in the transaction pool.
```go {3}
var content *txpool.ContentResponse
client.Call(
txpool.Content().Returns(&content),
)
```
## `txpool_contentFrom`
`ContentFrom` requests the pending and queued transactions in the transaction pool from the given address.
```go {3}
var contentFrom *txpool.ContentFromResponse
client.Call(
txpool.ContentFrom(addr).Returns(&contentFrom),
)
```
## `txpool_status`
`Status` requests the number of pending and queued transactions in the transaction pool.
```go {3}
var status *txpool.StatusResponse
client.Call(
txpool.Status().Returns(&status),
)
```
================================================
FILE: docs/pages/rpc-methods/web3.mdx
================================================
# `web3`-Namespace
List of supported RPC methods for `w3.Client` in the `web3`-namespace.
## `web3_clientVersion`
`ClientVersion` requests the endpoints client version.
```go {3}
var clientVersion string
client.Call(
web3.ClientVersion().Returns(&clientVersion),
)
```
================================================
FILE: docs/pages/rpc-methods.mdx
================================================
# Methods
`w3` supports most common RPC methods for Ethereum and other EVM chains. If you are in need of a method that is not supported by `w3` natively, you can use [third party method packages](#third-party-rpc-method-packages), or easily write a custom method-binding and use it with `w3`.
## RPC Namespaces
RPC methods supported by `w3` are grouped into namespaces.
<Cards>
<Card title="eth" href="/rpc-methods/eth"/>
<Card title="debug" href="/rpc-methods/debug"/>
<Card title="txpool" href="/rpc-methods/txpool"/>
<Card title="admin" href="/rpc-methods/admin"/>
<Card title="net" href="/rpc-methods/net"/>
<Card title="web3" href="/rpc-methods/web3" />
</Cards>
## Third Party RPC Method Packages
List of third party method packages that can be used with `w3.Client`.
| Package | Description
| :----------------------------------------------------------------------- | :-----------
| [github.com/lmittmann/flashbots](https://github.com/lmittmann/flashbots) | Package `flashbots` implements RPC API bindings for the Flashbots relay and mev-geth.
================================================
FILE: docs/pages/rpc-overview.mdx
================================================
# RPC Client
<DocLink title="w3.Client" /> is a blazing fast RPC client, built on top of `go-ethereum/rpc.Client`. It is designed for **batch requests** and **easy extendibility**.
## Get Started
<DocLink title="w3.Client" /> is a batch request focused RPC client that can be used to connect to an Ethereum node via HTTP, WebSocket, or IPC. Its modular API allows to create custom RPC method integrations that can be used alongside the common methods implemented by this package.
<Steps>
### Connect to an RPC Endpoint
Connect to an RPC endpoint via HTTP, WebSocket, or IPC using <DocLink title="w3.Dial" /> or <DocLink title="w3.MustDial" />.
```go
client, err := w3.Dial("https://eth.llamarpc.com")
if err != nil {
// ...
}
defer client.Close()
```
### Make a Request
Make a single HTTP request that calls two RPC methods.
```go
var (
balance *big.Int
nonce uint64
)
if err := client.Call(
eth.Balance(addr, nil).Returns(&balance),
eth.Nonce(addr, nil).Returns(&nonce),
); err != nil {
// ...
}
```
</Steps>
<Callout type="info">
#### Why send batch requests?
Most of the time you need to call multiple RPC methods to get the data you need. When you make separate requests per RPC call you need a single round trip to the server for each call. This can be slow, especially for remote endpoints. Batching multiple RPC calls into a single request only requires a single round trip, and speeds up RPC calls significantly.
</Callout>
## Call
<Callout type="info">Coming soon...</Callout>
## Call Contracts
<Callout type="info">Coming soon...</Callout>
## Subscribe
`w3.Client` supports subscriptions through the <DocLink title="Client.Subscribe" id="w3.Client.Subscribe" /> and <DocLink title="Client.SubscribeCtx" id="w3.Client.SubscribeCtx" /> methods. Subscriptions can be used to listen to events, emitted by the Ethereum node.
### Subscriptions
* `eth.NewHeads(ch chan<- *types.Header)`: Subscribe to new block headers.
* `eth.NewLogs(ch chan<- *types.Log, q ethereum.FilterQuery)`: Subscribe to new logs.
* `eth.PendingTransactions(ch chan<- *types.Transaction)`: Subscribe to new pending transactions.
#### Example: Subscribe to Pending Transactions
Subscribe to new pending transactions ([Playground](https://pkg.go.dev/github.com/lmittmann/w3##example-Client-SubscribeToPendingTransactions)):
```go
pendingTxCh := make(chan *types.Transaction)
sub, err := client.Subscribe(eth.PendingTransactions(pendingTxCh))
if err != nil {
// ...
}
for {
select {
case tx := <-pendingTxCh:
fmt.Printf("New pending tx: %s\n", tx.Hash())
case err := <-sub.Err():
fmt.Printf("Subscription error: %v\n", err)
return
}
}
```
## Error Handling
If one or more calls in a batch request fail, `Client.Call` returns an error of type <DocLink title="w3.CallErrors" />.
#### Example: `w3.CallErrors`
Check which RPC calls failed in a batch request ([Playground](https://pkg.go.dev/github.com/lmittmann/w3##example-Client-BatchHandleError))
```go
var batchErr w3.CallErrors
if err := client.Call(calls...); errors.As(err, &batchErr) {
// handle call errors
} else if err != nil {
// handle other errors
}
```
================================================
FILE: docs/pages/style.css
================================================
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
main {
@apply dark:text-neutral-300;
}
main strong,
main :not(a)>code {
@apply dark:text-white;
}
}
/* Headings */
h2 {
@apply border-none;
}
/* Links */
a._underline {
@apply no-underline;
}
/* Tables */
tr._border-gray-300 td,
tr._border-gray-300 th {
@apply dark:border-neutral-700;
}
tr._border-gray-300 {
@apply even:bg-neutral-900 !important;
}
/* Customize header */
.nextra-nav-container nav a[target="_blank"]:nth-child(2):after,
.nextra-nav-container nav a[target="_blank"]:nth-child(3):after,
.nextra-nav-container nav a[target="_blank"]:nth-child(4):after,
aside.nextra-sidebar-container li a[target="_blank"]:after {
content: url('data:image/svg+xml,<svg width="8" height="8" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8.33622 2.84025L1.17647 10L0 8.82354L7.15975 1.66378H0.849212V0H10V9.15081H8.33622V2.84025Z" fill="%239195A6"/></svg>');
@apply pl-2;
}
.nextra-nav-container nav a {
@apply font-semibold;
}
/* Customize sidebar */
aside.nextra-sidebar-container li._text-sm.\[word-break\:break-word\] {
@apply text-base;
}
aside.nextra-sidebar-container li._my-4.\[word-break\:break-word\] {
@apply mt-4 mb-0;
}
================================================
FILE: docs/pages/vm-overview.mdx
================================================
# VM
<DocLink title="w3vm.VM" /> is an easy-to-use Ethereum Virtual Machine (EVM), built on top of `go-ethereum`'s `vm.EVM`. It supports **tracing**, **state forking** via RPC, and can be used for simulation, debugging EVM execution, or testing Smart Contracts.
* **State forking** via RPC or custom state fetchers enables transaction simulations or Smart Contract tests on live, or historical chain state.
* **Tracing** of EVM execution is supported via `go-ethereum/core/tracing.Hooks`.
## Get Started
<Steps>
### Create a VM Instance
Create a VM instance, that forks the latest Mainnet state.
```go
client, err := w3.Dial("https://eth.llamarpc.com")
if err != nil {
// ...
}
defer client.Close()
vm, err := w3vm.New(
w3vm.WithFork(client, nil),
w3vm.WithNoBaseFee(),
)
if err != nil {
// ...
}
```
### Simulate a Simple Message
Transfer ETH from the zero address to a random recipient.
```go
recipient := w3vm.RandA()
receipt, err := vm.Apply(&w3types.Message{
From: common.Address{},
To: &recipient,
Value: w3.I("1 ether"),
})
if err != nil {
// ...
}
```
### Verify the Recipient's Balance
Verify the recipient's balance after the applied message.
```go
balance, err := vm.Balance(recipient)
if err != nil {
// ...
}
fmt.Printf("Balance: %s ETH\n", w3.FromWei(balance, 18))
// Output: Balance: 1 ETH
```
</Steps>
## Setup
A new VM instance is created using the `w3vm.New` function, which accepts various options to customize the VM behavior:
* `WithChainConfig(cfg *params.ChainConfig)`: Sets the chain configuration. If not provided, the VM defaults to the Mainnet configuration.
* `WithNoBaseFee()`: Forces the EIP-1559 base fee to 0.
* `WithBlockContext(ctx *vm.BlockContext)`: Sets the block context for the VM.
* `WithPrecompile(addr common.Address, contract vm.PrecompiledContract)`: Registers a precompile contract at the given address in the VM.
* `WithHeader(header *types.Header)`: Configures the block context for the VM using the provided header.
* `WithState(state w3types.State)`: Sets the pre-state of the VM. When used with `WithFork`, the pre-state overrides the forked state.
* `WithStateDB(db *state.StateDB)`: Specifies the state database for the VM, typically a snapshot from `VM.Snapshot`.
* `WithFork(client *w3.Client, blockNumber *big.Int)`: Forks state from a live Ethereum client at the specified block number.
* `WithFetcher(fetcher Fetcher)`: Assigns a fetcher to the VM.
* `WithTB(tb testing.TB)`: Enables persistent state caching when used in conjunction with `WithFork`.
## Execution
Messages represent transactions or contract calls that can be executed by the VM.
<Callout type="info">All execution methods support **tracing** via `go-ethereum/core/tracing.Hooks`. [Learn more ➔](/vm-tracing) </Callout>
### `Apply` Method
<DocLink title="Apply" id="w3vm.VM.Apply" /> applies a `w3types.Message` to the VM and returns a `Receipt`. If the execution doesn't revert, the VM's underlying state may change.
#### Example: Apply a Message
```go
msg := &w3types.Message{
From: addrSender,
To: &addrRecipient,
Value: w3.I("1 ether"),
Gas: 21000,
}
receipt, err := vm.Apply(msg)
if err != nil {
// ...
}
fmt.Printf("Gas Used: %d\n", receipt.GasUsed)
```
### `ApplyTx` Method
<DocLink title="ApplyTx" id="w3vm.VM.ApplyTx" /> is like `Apply`, but takes a `types.Transaction` instead of a message. The given transaction is converted to a message internally, using a signer, that is derived from the VM's chain configuration and fork block.
### `Call` Method
<DocLink title="Call" id="w3vm.VM.Call" /> is like `Apply`, but any state changes during execution are reverted in the end, so the VM's state is never modified.
#### Example: Call `balanceOf`
```go
funcBalanceOf := w3.MustNewFunc("balanceOf(address)", "uint256")
msg := &w3types.Message{
To: &addrToken,
Func: funcBalanceOf,
Args: []any{addrOwner},
}
receipt, err := vm.Call(msg)
if err != nil {
// handle error
}
var balance *big.Int
if err := receipt.DecodeReturns(&balance); err != nil {
// handle error
}
fmt.Printf("Balance: %s\n", balance)
```
### `CallFunc` Method
<DocLink title="CallFunc" id="w3vm.VM.CallFunc" /> is a helper, that greatly simplifies common usage of `Call`. It is designed analogues to the `eth.CallFunc` RPC client method.
#### Example: Call `balanceOf` with `CallFunc`
This is a simplified version of the [Call `balanceOf`](#example-call-balanceof) example.
```go
funcBalanceOf := w3.MustNewFunc("balanceOf(address)", "uint256")
var balance *big.Int
err := vm.CallFunc(addrToken, funcBalanceOf, addrOwner).Returns(&balance)
if err != nil {
// handle error
}
fmt.Printf("Balance: %s\n", balance)
```
### `Clone` Method
<DocLink title="Clone" id="w3vm.VM.Clone" /> returns a copy of the VM and its state. The cloned VM is independent of the original VM, and state changes do not affect the original VM.
### `Receipt` Type
The `Receipt` struct contains the result of an executed message.
#### Fields
* `GasUsed uint64`: Gas used for executing the message (including refunds).
* `MaxGasUsed uint64`: Maximum gas used during executing the message (excluding refunds).
* `Logs []*types.Log`: Logs emitted while executing the message.
* `Output []byte`: Output of the executed message.
* `ContractAddress *common.Address`: Address of the created contract, if any.
* `Err error`: Execution error, if any.
#### Methods
* `DecodeReturns(returns ...any) error`: Decodes the return values. This method only works, if the executed message had `w3types.Message.Func` set.
## State
The VM provides methods to read, and write account state.
### Reading State
* `vm.Balance(addr common.Address) (*big.Int, error)`: Returns the balance of the given address.
* `vm.Nonce(addr common.Address) (uint64, error)`: Returns the nonce of the given address.
* `vm.Code(addr common.Address) ([]byte, error)`: Returns the code of the given address.
* `vm.StorageAt(addr common.Address, slot common.Hash) (common.Hash, error)`: Returns the state of the given address at the given storage slot.
<Callout type="info">
An error only can only occur, if the VM fails to fetch state via a `w3vm.Fetcher`. Thus, it is safe to ignore the error, if no state fetcher is used by the VM.
</Callout>
### Writing State
* `vm.SetBalance(addr common.Address, balance *big.Int)`: Sets the balance of the given address.
* `vm.SetNonce(addr common.Address, nonce uint64)`: Sets the nonce of the given address.
* `vm.SetCode(addr common.Address, code []byte)`: Sets the code of the given address.
* `vm.SetStorageAt(addr common.Address, slot common.Hash, value common.Hash)`: Sets the state of the given address at the give storage slot.
## Helper
* `w3vm.RandA() common.Address`: Returns a random address.
* `WETHBalanceSlot(addr common.Address) common.Hash`: Returns the storage slot that stores the WETH balance of the given address.
* `WETHAllowanceSlot(owner, spender common.Address) common.Hash`: Returns the storage slot that stores the WETH allowance of the given owner to the spender.
### Storage Slot Calculation
Calculate storage slots for mappings. Solidity and Vyper use different parameter ordering for keccak256 hash calculation.
* `SoliditySlot(pos, key common.Hash) common.Hash`: Single mapping storage slot.
* `SoliditySlot2(pos, key0, key1 common.Hash) common.Hash`: Double mapping storage slot.
* `SoliditySlot3(pos, key0, key1, key2 common.Hash) common.Hash`: Triple mapping storage slot.
* `VyperSlot(pos, key common.Hash) common.Hash`: Single HashMap storage slot.
* `VyperSlot2(pos, key0, key1 common.Hash) common.Hash`: Double HashMap storage slot.
* `VyperSlot3(pos, key0, key1, key2 common.Hash) common.Hash`: Triple HashMap storage slot.
================================================
FILE: docs/pages/vm-testing.mdx
================================================
# Contract Testing
`w3vm` can be used to test Smart Contracts in Go utilizing Go's handy testing and fuzzing features.
<Callout type="warning">
`w3vm` **does not** natively support Smart Contract compilation.
</Callout>
## Compile Smart Contracts
The first step to testing a Smart Contract is usually to compile it to bytecode. There are a number of third party packages that provide compiler bindings in Go:
* [`go-solc`](https://github.com/lmittmann/go-solc): Go bindings for the Solidity compiler (`solc`)
* [`go-huffc`](https://github.com/project-blanc/go-huffc): Go Bindings for the Huff Compiler (`huffc`)
* [`geas`](https://github.com/fjl/geas): The Good Ethereum Assembler
## Setup a `w3vm.VM`
Before a Smart Contract can be tested with a `w3vm.VM` instance, its bytecode must be deployed to the VM. This can be done in two ways, depending on whether constructor logic is present.
### Without Constructor Logic
If the Smart Contract does not require constructor logic, its runtime bytecode can be directly set as the bytecode of an address:
```go
contractRuntime = w3.B("0x...")
contractAddr := w3vm.RandA()
vm, _ := w3vm.New(
w3vm.WithState(w3types.State{
contractAddr: {Code: runtime},
}),
)
```
### With Constructor Logic
If the Smart Contract requires constructor logic, the constructor bytecode must be sent in a standard deployment transaction (`w3types.Message`) without recipient:
```go
contractConstructor := w3.B("0x...")
deployerAddr := w3vm.RandA()
vm, _ := w3vm.New()
receipt, err := vm.Apply(&w3types.Message{
From: deployerAddr,
Input: contractConstructor,
})
if err != nil || receipt.ContractAddress == nil {
// ...
}
contractAddr := *receipt.ContractAddress
```
### Custom State
The state of the VM can be fully customized using the `w3vm.WithState` option. This allows, e.g., setting a balance for addresses that interact with the Smart Contract. State can also be modified after the VM is created using the [state write methods](/vm-overview#writing-state).
### State Forking
If the tested Smart Contract interacts with other existing contracts, the VM can be configured to fork the state at a specific block number (or the latest block). This enables testing contracts in a real-world environment.
```go
client := w3.MustDial("https://eth.llamarpc.com")
defer client.Close()
vm, err := w3vm.New(
w3vm.WithFork(client, big.NewInt(20_000_000)),
w3vm.WithNoBaseFee(),
w3vm.WithTB(t),
)
if err != nil {
// ...
}
```
<Callout>
`w3vm.WithTB(t)` can be used in tests or benchmarks to **cache state**. The VM persists this cached state in `{package of test}/testdata/w3vm/`. This is particularly useful when working with public RPC providers, as it reduces the number of requests and significantly speeds up test execution.
</Callout>
## Testing
Testing Smart Contracts with `w3vm` follows the standard Go testing patterns using the package `testing`. By integrating `w3vm` into your tests, you can simulate blockchain interactions and validate Smart Contract behaviors within your test cases.
#### Example: Test WETH `deposit` Function
Test of the WETH `deposit` function.
```go
func TestWETHDeposit(t *testing.T) {
// setup VM
vm, _ := w3vm.New(
w3vm.WithState(w3types.State{
addrWETH: {Code: codeWETH},
addrA: {Balance: w3.I("1 ether")},
}),
)
// pre check
var wethBalanceBefore *big.Int
if err := vm.CallFunc(addrWETH, funcBalanceOf, addrA).Returns(&wethBalanceBefore); err != nil {
t.Fatal(err)
}
if wethBalanceBefore.Sign() != 0 {
t.Fatal("Invalid WETH balance: want 0")
}
// deposit (via fallback)
if _, err := vm.Apply(&w3types.Message{
From: addrA,
To: &addrWETH,
Value: w3.I("1 ether"),
}); err != nil {
t.Fatalf("Deposit failed: %v", err)
}
// post check
var wethBalanceAfter *big.Int
if err := vm.CallFunc(addrWETH, funcBalanceOf, addrA).Returns(&wethBalanceAfter); err != nil {
t.Fatal(err)
}
if w3.I("1 ether").Cmp(wethBalanceAfter) != 0 {
t.Fatalf("Invalid WETH balance: want 1")
}
}
```
## Fuzz Testing
Fuzzing Smart Contracts with `w3vm` leverages Go's fuzz testing capabilities to automatically generate a wide range of inputs for your contracts. By incorporating `w3vm` into your fuzzing tests, you can effectively discover vulnerabilities and unexpected behaviors in your Smart Contracts.
#### Example: Fuzz Test WETH `deposit` Function
Fuzz test of the WETH `deposit` function.
```go
func FuzzWETHDeposit(f *testing.F) {
f.Add([]byte{1})
f.Fuzz(func(t *testing.T, amountBytes []byte) {
if len(amountBytes) > 32 {
t.Skip()
}
amount := new(big.Int).SetBytes(amountBytes)
// setup VM
vm, _ := w3vm.New(
w3vm.WithState(w3types.State{
addrWETH: {Code: codeWETH},
addrA: {Balance: w3.BigMaxUint256},
}),
)
// Pre-check WETH balance
var wethBalanceBefore *big.Int
if err := vm.CallFunc(addrWETH, funcBalanceOf, addrA).Returns(&wethBalanceBefore); err != nil {
t.Fatal(err)
}
// Attempt deposit
vm.Apply(&w3types.Message{
From: addrA,
To: &addrWETH,
Value: amount,
})
// Post-check WETH balance
var wethBalanceAfter *big.Int
if err := vm.CallFunc(addrWETH, funcBalanceOf, addrA).Returns(&wethBalanceAfter); err != nil {
t.Fatal(err)
}
// Verify balance increment
wantBalance := new(big.Int).Add(wethBalanceBefore, amount)
if wethBalanceAfter.Cmp(wantBalance) != 0 {
t.Fatalf("Invalid WETH balance: want %s, got %s", wantBalance, wethBalanceAfter)
}
})
}
```
================================================
FILE: docs/pages/vm-tracing.mdx
================================================
# Tracing
Tracing can give detailed insights into the execution of EVM contracts. `w3vm.VM` supports tracing via `go‑ethereum`'s <DocLink title="tracing.Hooks" />.
## Usage
A `tracing.Hooks` can be passed to <DocLink title="VM.Apply" id="w3vm.VM.Apply" />, <DocLink title="VM.ApplyTx" id="w3vm.VM.ApplyTx" />, and <DocLink title="VM.Call" id="w3vm.VM.Call" />. These methods can also be called with multiple hooks at the same time.
#### Example: Trace Calls and OpCodes of an Execution
`w3vm` contains a powerful call an opcode tracer <DocLink title="hooks.CallTracer" id="hooks.NewCallTracer" /> that can be used gain detailed insights into the execution of EVM contracts ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-Trace)):
```go
callTracer := hooks.NewCallTracer(os.Stdout, &hooks.CallTracerOptions{
ShowStaticcall: true,
DecodeABI: true,
})
vm.ApplyTx(tx, callTracer)
```

#### Example: Generate an Access List
Access list tracing using `go-ethereum`'s <DocLink title="logger.AccessListTracer" /> ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-TraceAccessList)):
```go {2-8}
// setup access list tracer
signer := types.MakeSigner(params.MainnetChainConfig, header.Number, header.Time)
from, _ := signer.Sender(tx)
accessListTracer := logger.NewAccessListTracer(
nil,
from, *tx.To(),
gethVm.ActivePrecompiles(params.MainnetChainConfig.Rules(header.Number, header.Difficulty.Sign() == 0, header.Time)),
)
if _, err := vm.ApplyTx(tx, accessListTracer.Hooks()); err != nil {
// ...
}
fmt.Println("Access List:", accessListTracer.AccessList())
```
#### Example: Trace the Execution of all OpCodes in a Block
Trace the execution of all op's in a block ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM-TraceBlock)):
```go {2-7}
// setup block op's tracer
var opCount [256]uint64
tracer := &tracing.Hooks{
OnOpcode: func(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
opCount[op]++
},
}
for _, tx := range block.Transactions() {
vm.ApplyTx(tx, tracer)
}
```
================================================
FILE: docs/postcss.config.cjs
================================================
module.exports = {
plugins: {
"tailwindcss/nesting": {},
tailwindcss: {},
autoprefixer: {},
},
};
================================================
FILE: docs/public/_redirects
================================================
/vm /vm-overview
/rpc /rpc-overview
/abi /helper-abi
================================================
FILE: docs/public/robots.txt
================================================
User-agent: *
Allow: /
================================================
FILE: docs/tailwind.config.js
================================================
module.exports = {
content: [
'./pages/**/*.{js,jsx,mdx}',
'./components/**/*.{js,jsx}',
'./theme.config.jsx'
],
theme: {
extend: {}
},
plugins: [],
darkMode: 'class'
}
================================================
FILE: docs/theme.config.jsx
================================================
import Image from 'next/image'
import { useConfig } from 'nextra-theme-docs'
import { Callout, Cards, Steps } from 'nextra/components'
import { DocLink } from './components/DocLink'
export default {
logo: <>
<div className="rounded-full h-10 w-10 mr-2 overflow-hidden bg-black/10 dark:bg-white/10">
<Image src="/gopher.png" alt="w3" width={48} height={48} className='w-11/12 mx-auto' />
</div>
<span className="text-2xl font-bold">w3</span>
</>,
head: () => {
const { frontMatter } = useConfig()
const title = frontMatter.title ? `${frontMatter.title} – w3` : 'w3'
return (
<>
<title>{title}</title>
<meta property="og:title" content={title} />
<meta
property="og:description"
content={frontMatter.description || 'w3'}
/>
</>
)
},
footer: {
component: null,
},
components: {
Callout: Callout,
Card: Cards.Card,
Cards: Cards,
Image: Image,
Steps: Steps,
DocLink: DocLink,
},
project: {
link: 'https://github.com/lmittmann/w3',
},
chat: {
link: 'https://t.me/w3_golang',
icon: (
<svg width="24" height="24" viewBox="0 0 48 48" fill="currentColor">
<path d="M41.4193 7.30899C41.4193 7.30899 45.3046 5.79399 44.9808 9.47328C44.8729 10.9883 43.9016 16.2908 43.1461 22.0262L40.5559 39.0159C40.5559 39.0159 40.3401 41.5048 38.3974 41.9377C36.4547 42.3705 33.5408 40.4227 33.0011 39.9898C32.5694 39.6652 24.9068 34.7955 22.2086 32.4148C21.4531 31.7655 20.5897 30.4669 22.3165 28.9519L33.6487 18.1305C34.9438 16.8319 36.2389 13.8019 30.8426 17.4812L15.7331 27.7616C15.7331 27.7616 14.0063 28.8437 10.7686 27.8698L3.75342 25.7055C3.75342 25.7055 1.16321 24.0823 5.58815 22.459C16.3807 17.3729 29.6555 12.1786 41.4193 7.30899Z" />
</svg>
)
},
feedback: {
content: null,
},
docsRepositoryBase: 'https://github.com/lmittmann/w3/blob/main/docs',
color: {
hue: 189,
saturation: 100,
},
}
================================================
FILE: event.go
================================================
package w3
import (
"fmt"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
_abi "github.com/lmittmann/w3/internal/abi"
)
// Event represents a Smart Contract event decoder.
type Event struct {
Signature string // Event signature
Topic0 common.Hash // Hash of event signature (Topic 0)
Args abi.Arguments // Arguments
indexedArgs abi.Arguments // Subset of Args that are indexed
}
// NewEvent returns a new Smart Contract event log decoder from the given
// Solidity event signature.
//
// The optional tuples parameter accepts struct definitions that can be
// referenced by name in the signature instead of using inline tuple
// definitions. This enables cleaner, more readable function signatures when
// working with complex tuple types.
//
// An error is returned if the signature parsing fails.
func NewEvent(signature string, tuples ...any) (*Event, error) {
name, args, err := _abi.ParseWithName(signature, tuples...)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrInvalidABI, err)
}
if name == "" {
return nil, fmt.Errorf("%w: missing event name", ErrInvalidABI)
}
indexedArgs := make(abi.Arguments, 0)
for _, arg := range args {
if arg.Indexed {
arg.Indexed = false
indexedArgs = append(indexedArgs, arg)
}
}
sig := args.SignatureWithName(name)
return &Event{
Signature: sig,
Topic0: crypto.Keccak256Hash([]byte(sig)),
Args: abi.Arguments(args),
indexedArgs: indexedArgs,
}, nil
}
// MustNewEvent is like [NewEvent] but panics if the signature parsing fails.
func MustNewEvent(signature string, tuples ...any) *Event {
event, err := NewEvent(signature, tuples...)
if err != nil {
panic(err)
}
return event
}
// DecodeArgs decodes the topics and data of the given log to the given args.
func (e *Event) DecodeArgs(log *types.Log, args ...any) error {
if len(log.Topics) <= 0 || e.Topic0 != log.Topics[0] {
return fmt.Errorf("w3: topic0 mismatch")
}
if len(e.Args) != len(args) {
return fmt.Errorf("%w: expected %d arguments, got %d", ErrArgumentMismatch, len(e.Args), len(args))
}
if len(e.indexedArgs) != len(log.Topics)-1 {
return fmt.Errorf("%w: expected %d indexed arguments, got %d", ErrArgumentMismatch, len(e.indexedArgs), len(log.Topics)-1)
}
indexedArgs := make([]any, 0, len(e.indexedArgs))
nonIndexedArgs := make([]any, 0, len(e.Args)-len(e.indexedArgs))
for i, arg := range e.Args {
if arg.Indexed {
indexedArgs = append(indexedArgs, args[i])
} else {
nonIndexedArgs = append(nonIndexedArgs, args[i])
}
}
// decode indexed args
for i, arg := range indexedArgs {
if err := (_abi.Arguments{e.indexedArgs[i]}).Decode(log.Topics[i+1][:], arg); err != nil {
return err
}
}
// decode non-indexed args
if err := _abi.Arguments(e.Args).Decode(log.Data, nonIndexedArgs...); err != nil {
return err
}
return nil
}
================================================
FILE: event_test.go
================================================
package w3_test
import (
"math/big"
"strconv"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/lmittmann/w3"
)
func TestNewEvent(t *testing.T) {
tests := []struct {
Signature string
WantEvent *w3.Event
}{
{
Signature: "Transfer(address,address,uint256)",
WantEvent: &w3.Event{
Signature: "Transfer(address,address,uint256)",
Topic0: w3.H("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"),
},
},
{
Signature: "Transfer(address from, address to, uint256 value)",
WantEvent: &w3.Event{
Signature: "Transfer(address,address,uint256)",
Topic0: w3.H("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"),
},
},
{
Signature: "Approval(address,address,uint256)",
WantEvent: &w3.Event{
Signature: "Approval(address,address,uint256)",
Topic0: w3.H("0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"),
},
},
{
Signature: "Approval(address owner, address spender, uint256 value)",
WantEvent: &w3.Event{
Signature: "Approval(address,address,uint256)",
Topic0: w3.H("0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"),
},
},
}
for i, test := range tests {
t.Run(strconv.Itoa(i), func(t *testing.T) {
gotEvent, err := w3.NewEvent(test.Signature)
if err != nil {
t.Fatalf("Failed to create new FUnc: %v", err)
}
if diff := cmp.Diff(test.WantEvent, gotEvent,
cmpopts.IgnoreUnexported(w3.Event{}),
cmpopts.IgnoreFields(w3.Event{}, "Args"),
); diff != "" {
t.Fatalf("(-want, +got)\n%s", diff)
}
})
}
}
func TestEventDecodeArgs(t *testing.T) {
tests := []struct {
Event *w3.Event
Log *types.Log
Args []any
WantArgs []any
}{
{
Event: w3.MustNewEvent("Transfer(address,address,uint256)"),
Log: &types.Log{
Topics: []common.Hash{
w3.H("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"),
},
Data: w3.B("0x" +
"000000000000000000000000000000000000000000000000000000000000c0fe" +
"000000000000000000000000000000000000000000000000000000000000dead" +
"000000000000000000000000000000000000000000000000000000000000002a"),
},
Args: []any{new(common.Address), new(common.Address), new(big.Int)},
WantArgs: []any{
w3.APtr("0x000000000000000000000000000000000000c0Fe"),
w3.APtr("0x000000000000000000000000000000000000dEaD"),
big.NewInt(42),
},
},
{
Event: w3.MustNewEvent("Transfer(address indexed, address, uint256)"),
Log: &types.Log{
Topics: []common.Hash{
w3.H("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"),
w3.H("0x000000000000000000000000000000000000000000000000000000000000c0fe"),
},
Data: w3.B("0x" +
"000000000000000000000000000000000000000000000000000000000000dead" +
"000000000000000000000000000000000000000000000000000000000000002a"),
},
Args: []any{new(common.Address), new(common.Address), new(big.Int)},
WantArgs: []any{
w3.APtr("0x000000000000000000000000000000000000c0Fe"),
w3.APtr("0x000000000000000000000000000000000000dEaD"),
big.NewInt(42),
},
},
{
Event: w3.MustNewEvent("Transfer(address, address indexed, uint256)"),
Log: &types.Log{
Topics: []common.Hash{
w3.H("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"),
w3.H("0x000000000000000000000000000000000000000000000000000000000000dead"),
},
Data: w3.B("0x" +
"000000000000000000000000000000000000000000000000000000000000c0fe" +
"000000000000000000000000000000000000000000000000000000000000002a"),
},
Args: []any{new(common.Address), new(common.Address), new(big.Int)},
WantArgs: []any{
w3.APtr("0x000000000000000000000000000000000000c0Fe"),
w3.APtr("0x000000000000000000000000000000000000dEaD"),
big.NewInt(42),
},
},
{
Event: w3.MustNewEvent("Transfer(address indexed, address indexed, uint256)"),
Log: &types.Log{
Topics: []common.Hash{
w3.H("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"),
w3.H("0x000000000000000000000000000000000000000000000000000000000000c0fe"),
w3.H("0x000000000000000000000000000000000000000000000000000000000000dead"),
},
Data: w3.B("0x000000000000000000000000000000000000000000000000000000000000002a"),
},
Args: []any{new(common.Address), new(common.Address), new(big.Int)},
WantArgs: []any{
w3.APtr("0x000000000000000000000000000000000000c0Fe"),
w3.APtr("0x000000000000000000000000000000000000dEaD"),
big.NewInt(42),
},
},
{
Event: w3.MustNewEvent("Transfer(address indexed, address indexed, uint256 indexed)"),
Log: &types.Log{
Topics: []common.Hash{
w3.H("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"),
w3.H("0x000000000000000000000000000000000000000000000000000000000000c0fe"),
w3.H("0x000000000000000000000000000000000000000000000000000000000000dead"),
w3.H("0x000000000000000000000000000000000000000000000000000000000000002a"),
},
},
Args: []any{new(common.Address), new(common.Address), new(big.Int)},
WantArgs: []any{
w3.APtr("0x000000000000000000000000000000000000c0Fe"),
w3.APtr("0x000000000000000000000000000000000000dEaD"),
big.NewInt(42),
},
},
{ // https://github.com/lmittmann/w3/issues/15
Event: w3.MustNewEvent("NameRegistered(string name, bytes32 indexed label, address indexed owner, uint cost, uint expires)"),
Log: &types.Log{
Address: w3.A("0x283Af0B28c62C092C9727F1Ee09c02CA627EB7F5"),
Topics: []common.Hash{
w3.H("0xca6abbe9d7f11422cb6ca7629fbf6fe9efb1c621f71ce8f02b9f2a230097404f"),
w3.H("0x4e59ffc7ae105a2b19f7f29b63e9f9c5ac28e27bce744a330804c6a89269cec0"),
w3.H("0x000000000000000000000000bd08f39b2523426cc1d6961e2d6a9744b3b432b5"),
},
Data: w3.B("0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000165a7d3a3e48ad0000000000000000000000000000000000000000000000000000000066e4d0a50000000000000000000000000000000000000000000000000000000000000009656c666172657373690000000000000000000000000000000000000000000000"),
},
Args: []any{new(string), new(common.Hash), new(common.Address), new(big.Int), new(big.Int)},
WantArgs: []any{
ptr("elfaressi"),
ptr(w3.H("0x4e59ffc7ae105a2b19f7f29b63e9f9c5ac28e27bce744a330804c6a89269cec0")),
w3.APtr("0xbD08F39B2523426Cc1d6961e2d6A9744B3B432b5"),
big.NewInt(6291943382206637),
big.NewInt(1726271653),
},
},
}
for i, test := range tests {
t.Run(strconv.Itoa(i), func(t *testing.T) {
if err := test.Event.DecodeArgs(test.Log, test.Args...); err != nil {
t.Fatalf("Failed to decode args: %v", err)
}
if diff := cmp.Diff(test.WantArgs, test.Args,
cmp.AllowUnexported(big.Int{}),
cmpopts.IgnoreUnexported(w3.Event{}),
); diff != "" {
t.Fatalf("(-want, +got)\n%s", diff)
}
})
}
}
================================================
FILE: example_test.go
================================================
package w3_test
import (
"crypto/ecdsa"
"errors"
"fmt"
"math/big"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
"github.com/lmittmann/w3"
"github.com/lmittmann/w3/module/eth"
"github.com/lmittmann/w3/w3types"
"github.com/lmittmann/w3/w3vm"
"golang.org/x/time/rate"
)
var (
funcName = w3.MustNewFunc("name()", "string")
funcSymbol = w3.MustNewFunc("symbol()", "string")
funcDecimals = w3.MustNewFunc("decimals()", "uint8")
funcBalanceOf = w3.MustNewFunc("balanceOf(address)", "uint256")
addrA = common.Address{0x0a}
addrB = common.Address{0x0b}
prvA *ecdsa.PrivateKey // dummy private key for addrA
addrWETH = w3.A("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2")
addrDAI = w3.A("0x6B175474E89094C44Da98b954EedeAC495271d0F")
client = w3.MustDial("https://ethereum-rpc.publicnode.com")
)
// Call the name, symbol, decimals, and balanceOf functions of the Wrapped Ether
// in a single batch.
func ExampleClient_batchCallFunc() {
blockNumber := big.NewInt(20_000_000)
var (
name, symbol string
decimals uint8
balance big.Int
)
if err := client.Call(
eth.CallFunc(addrWETH, funcName).Returns(&name),
eth.CallFunc(addrWETH, funcSymbol).Returns(&symbol),
eth.CallFunc(addrWETH, funcDecimals).Returns(&decimals),
eth.CallFunc(addrWETH, funcBalanceOf, addrWETH).AtBlock(blockNumber).Returns(&balance),
); err != nil {
// ...
}
fmt.Printf("%s's own balance: %s %s\n", name, w3.FromWei(&balance, decimals), symbol)
// Output:
// Wrapped Ether's own balance: 748.980125465356473638 WETH
}
// Call the Uniswap V3 Quoter for quotes on swapping 100 WETH for DAI in pools
// of all fee tiers in a single batch.
func ExampleClient_batchCallFuncUniswapQuoter() {
blockNumber := big.NewInt(20_000_000)
var (
addrUniswapV3Quoter = w3.A("0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6")
addrTokenIn = addrWETH
addrTokenOut = addrDAI
funcQuote = w3.MustNewFunc(`quoteExactInputSingle(
address tokenIn,
address tokenOut,
uint24 fee,
uint256 amountIn,
uint160 sqrtPriceLimitX96clear
)`, "uint256 amountOut")
)
var (
amountIn = w3.I("100 ether")
amountOut100 *big.Int
amountOut500 *big.Int
amountOut3000 *big.Int
amountOut10000 *big.Int
)
if err := client.Call(
eth.CallFunc(addrUniswapV3Quoter, funcQuote, addrTokenIn, addrTokenOut, big.NewInt(100), amountIn, w3.Big0).AtBlock(blockNumber).Returns(&amountOut100),
eth.CallFunc(addrUniswapV3Quoter, funcQuote, addrTokenIn, addrTokenOut, big.NewInt(500), amountIn, w3.Big0).AtBlock(blockNumber).Returns(&amountOut500),
eth.CallFunc(addrUniswapV3Quoter, funcQuote, addrTokenIn, addrTokenOut, big.NewInt(3000), amountIn, w3.Big0).AtBlock(blockNumber).Returns(&amountOut3000),
eth.CallFunc(addrUniswapV3Quoter, funcQuote, addrTokenIn, addrTokenOut, big.NewInt(10000), amountIn, w3.Big0).AtBlock(blockNumber).Returns(&amountOut10000),
); err != nil {
// ...
}
fmt.Println("Swap 100 WETH for DAI:")
fmt.Printf("Pool with 0.01%% fee: %s DAI\n", w3.FromWei(amountOut100, 18))
fmt.Printf("Pool with 0.05%% fee: %s DAI\n", w3.FromWei(amountOut500, 18))
fmt.Printf("Pool with 0.3%% fee: %s DAI\n", w3.FromWei(amountOut3000, 18))
fmt.Printf("Pool with 1%% fee: %s DAI\n", w3.FromWei(amountOut10000, 18))
// Output:
// Swap 100 WETH for DAI:
// Pool with 0.01% fee: 0.840975419471618588 DAI
// Pool with 0.05% fee: 371877.453117609415215338 DAI
// Pool with 0.3% fee: 378532.856217317782434539 DAI
// Pool with 1% fee: 3447.634026125332130689 DAI
}
// Fetch the nonce and balance of an EOA in a single batch.
func ExampleClient_batchEOAState() {
var (
nonce uint64
balance *big.Int
)
if err := client.Call(
eth.Nonce(addrA, nil).Returns(&nonce),
eth.Balance(addrA, nil).Returns(&balance),
); err != nil {
// ...
}
fmt.Printf("Nonce: %d\nBalance: %d\n", nonce, balance)
}
// Fetch a transaction and its receipt in a single batch.
func ExampleClient_batchTxDetails() {
txHash := w3.H("0xc31d7e7e85cab1d38ce1b8ac17e821ccd47dbde00f9d57f2bd8613bff9428396")
var (
tx *types.Transaction
receipt *types.Receipt
)
if err := client.Call(
eth.Tx(txHash).Returns(&tx),
eth.TxReceipt(txHash).Returns(&receipt),
); err != nil {
// ...
}
fmt.Printf("Tx: %#v\nReceipt: %#v\n", tx, receipt)
}
// Fetch 1000 blocks in batches.
func ExampleClient_batchBlocks() {
const (
startBlock = 20_000_000
nBlocks = 1000
batchSize = 100
)
blocks := make([]*types.Block, nBlocks)
calls := make([]w3types.RPCCaller, batchSize)
for i := 0; i < nBlocks; i += batchSize {
for j := range batchSize {
blockNumber := new(big.Int).SetUint64(uint64(startBlock + i + j))
calls[j] = eth.BlockByNumber(blockNumber).Returns(&blocks[i+j])
}
if err := client.Call(calls...); err != nil {
// ...
}
fmt.Printf("Fetched %d blocks\n", i+batchSize)
}
}
// Handle errors of individual calls in a batch.
func ExampleClient_batchHandleError() {
tokens := []common.Address{addrWETH, addrA, addrB}
symbols := make([]string, len(tokens))
// build rpc calls
calls := make([]w3types.RPCCaller, len(tokens))
for i, token := range tokens {
calls[i] = eth.CallFunc(token, funcSymbol).Returns(&symbols[i])
}
var batchErr w3.CallErrors
if err := client.Call(calls...); errors.As(err, &batchErr) {
} else if err != nil {
// all calls failed
}
for i, symbol := range symbols {
if len(batchErr) > 0 && batchErr[i] != nil {
symbol = "call failed"
}
fmt.Printf("%s: %s\n", tokens[i], symbol)
}
// Output:
// 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2: WETH
// 0x0a00000000000000000000000000000000000000: call failed
// 0x0B00000000000000000000000000000000000000: call failed
}
// Fetch the token balance of an address.
func ExampleClient_callFunc() {
var balance *big.Int
if err := client.Call(
eth.CallFunc(addrWETH, funcBalanceOf, addrA).Returns(&balance),
); err != nil {
// ...
}
fmt.Printf("Balance: %s WETH\n", w3.FromWei(balance, 18))
// Output:
// Balance: 0 WETH
}
// Fetch the token balance of an address, with state override.
func ExampleClient_callFuncWithStateOverride() {
var balance *big.Int
if err := client.Call(
eth.CallFunc(addrWETH, funcBalanceOf, addrA).Overrides(w3types.State{
addrWETH: {Storage: w3types.Storage{
w3vm.WETHBalanceSlot(addrA): common.BigToHash(w3.I("100 ether")),
}},
}).Returns(&balance),
); err != nil {
// ...
}
fmt.Printf("Balance: %s WETH\n", w3.FromWei(balance, 18))
// Output:
// Balance: 100 WETH
}
// Send Ether transfer.
func ExampleClient_sendETHTransfer() {
var (
nonce uint64
gasPrice *big.Int
)
if err := client.Call(
eth.Nonce(addrA, nil).Returns(&nonce),
eth.GasPrice().Returns(&gasPrice),
); err != nil {
// ...
}
signer := types.LatestSigner(params.MainnetChainConfig)
tx := types.MustSignNewTx(prvA, signer, &types.LegacyTx{
Nonce: nonce,
Gas: 21_000,
GasPrice: gasPrice,
To: &addrB,
Value: w3.I("1 ether"),
})
var txHash common.Hash
if err := client.Call(eth.SendTx(tx).Returns(&txHash)); err != nil {
// ...
}
fmt.Printf("Sent tx: %s\n", txHash)
}
// Send ERC20 token transfer (Wrapped Ether).
func ExampleClient_sendTokenTransfer() {
var (
nonce uint64
gasPrice *big.Int
)
if err := client.Call(
eth.Nonce(addrA, nil).Returns(&nonce),
eth.GasPrice().Returns(&gasPrice),
); err != nil {
// ...
}
funcTransfer := w3.MustNewFunc("transfer(address receiver, uint256 amount)", "bool")
data, err := funcTransfer.EncodeArgs(addrB, w3.I("1 ether"))
if err != nil {
// ...
}
signer := types.LatestSigner(params.MainnetChainConfig)
tx := types.MustSignNewTx(prvA, signer, &types.LegacyTx{
Nonce: nonce,
Gas: 100_000,
GasPrice: gasPrice,
To: &addrWETH,
Data: data,
})
var txHash common.Hash
if err := client.Call(eth.SendTx(tx).Returns(&txHash)); err != nil {
// ...
}
fmt.Printf("Sent tx: %s\n", txHash)
}
// Subscribe to pending transactions.
func ExampleClient_subscribeToPendingTransactions() {
client, err := w3.Dial("wss://mainnet.gateway.tenderly.co")
if err != nil {
// ...
}
defer client.Close()
pendingTxCh := make(chan *types.Transaction)
sub, err := client.Subscribe(eth.PendingTransactions(pendingTxCh))
if err != nil {
// ...
}
for {
select {
case tx := <-pendingTxCh:
fmt.Printf("New pending tx: %s\n", tx.Hash())
case err := <-sub.Err():
fmt.Printf("Subscription error: %v\n", err)
return
}
}
}
// Rate Limit the number of requests to 10 per second, with bursts of up to 20
// requests.
func ExampleClient_rateLimitByRequest() {
client, err := w3.Dial("https://ethereum-rpc.publicnode.com",
w3.WithRateLimiter(rate.NewLimiter(rate.Every(time.Second/10), 20), nil),
)
if err != nil {
// ...
}
defer client.Close()
}
// Rate Limit the number of requests to 300 compute units (CUs) per second, with
// bursts of up to 300 CUs.
// An individual CU can be charged per RPC method call.
func ExampleClient_rateLimitByComputeUnits() {
// cu returns the CU cost for all method calls in a batch.
cu := func(methods []string) (cost int) {
for _, method := range methods {
switch method {
case "eth_blockNumber":
cost += 5
case "eth_getBalance",
"eth_getBlockByNumber",
"eth_getCode",
"eth_getStorageAt",
"eth_getTransactionByHash",
"eth_getTransactionReceipt":
cost += 15
case "eth_call":
cost += 20
case "eth_getTransactionCount":
cost += 25
default:
panic(fmt.Sprintf("unknown costs for %q", method))
}
}
return cost
}
client, err := w3.Dial("https://ethereum-rpc.publicnode.com",
w3.WithRateLimiter(rate.NewLimiter(rate.Every(time.Second/300), 300), cu),
)
if err != nil {
// ...
}
defer client.Close()
}
// ABI bindings for the ERC20 functions.
func ExampleFunc_erc20() {
var (
funcTotalSupply = w3.MustNewFunc("totalSupply()", "uint256")
funcBalanceOf = w3.MustNewFunc("balanceOf(address)", "uint256")
funcTransfer = w3.MustNewFunc("transfer(address to, uint256 amount)", "bool")
funcAllowance = w3.MustNewFunc("allowance(address owner, address spender)", "uint256")
funcApprove = w3.MustNewFunc("approve(address spender, uint256 amount)", "bool")
funcTransferFrom = w3.MustNewFunc("transferFrom(address from, address to, uint256 amount)", "bool")
)
_ = funcTotalSupply
_ = funcBalanceOf
_ = funcTransfer
_ = funcAllowance
_ = funcApprove
_ = funcTransferFrom
}
// Encode and decode the arguments of the balanceOf function.
func ExampleFunc_balanceOf() {
// encode
input, err := funcBalanceOf.EncodeArgs(addrA)
if err != nil {
// ...
}
fmt.Printf("encoded: 0x%x\n", input)
// decode
var who common.Address
if err := funcBalanceOf.DecodeArgs(input, &who); err != nil {
// ...
}
fmt.Printf("decoded: balanceOf(%s)\n", who)
// Output:
// encoded: 0x70a082310000000000000000000000000a00000000000000000000000000000000000000
// decoded: balanceOf(0x0a00000000000000000000000000000000000000)
}
// ABI bindings for the Uniswap v4 swap function.
func ExampleFunc_uniswapV4Swap() {
// ABI binding for the PoolKey struct.
type PoolKey struct {
Currency0 common.Address
Currency1 common.Address
Fee *big.Int `abitype:"uint24"`
TickSpacing *big.Int `abitype:"int24"`
Hooks common.Address
}
// ABI binding for the SwapParams struct.
type SwapParams struct {
ZeroForOne bool
AmountSpecified *big.Int `abitype:"int256"`
SqrtPriceLimitX96 *big.Int `abitype:"uint160"`
}
funcSwap := w3.MustNewFunc(`swap(PoolKey key, SwapParams params, bytes hookData)`, "int256 delta",
PoolKey{}, SwapParams{},
)
// encode
input, _ := funcSwap.EncodeArgs(
&PoolKey{
Currency0: addrWETH,
Currency1: addrDAI,
Fee: big.NewInt(0),
TickSpacing: big.NewInt(0),
},
&SwapParams{
ZeroForOne: false,
AmountSpecified: big.NewInt(0),
SqrtPriceLimitX96: big.NewInt(0),
},
[]byte{},
)
fmt.Printf("encoded: 0x%x\n", input)
// Output:
// encoded: 0xf3cd914c000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000000
}
func ExampleFunc_DecodeReturns_getReserves() {
funcGetReserves := w3.MustNewFunc("getReserves()", "uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast")
output := w3.B(
"0x00000000000000000000000000000000000000000000003635c9adc5dea00000",
"0x0000000000000000000000000000000000000000000000a2a15d09519be00000",
"0x0000000000000000000000000000000000000000000000000000000064373057",
)
var (
reserve0, reserve1 *big.Int
blockTimestampLast uint32
)
if err := funcGetReserves.DecodeReturns(output, &reserve0, &reserve1, &blockTimestampLast); err != nil {
// ...
}
fmt.Println("Reserve0:", reserve0)
fmt.Println("Reserve1:", reserve1)
fmt.Println("BlockTimestampLast:", blockTimestampLast)
// Output:
// Reserve0: 1000000000000000000000
// Reserve1: 3000000000000000000000
// BlockTimestampLast: 1681338455
}
func ExampleEvent_decodeTransferEvent() {
var (
eventTransfer = w3.MustNewEvent("Transfer(address indexed from, address indexed to, uint256 value)")
log = &types.Log{
Address: w3.A("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"),
Topics: []common.Hash{
w3.H("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"),
w3.H("0x000000000000000000000000000000000000000000000000000000000000c0fe"),
w3.H("0x000000000000000000000000000000000000000000000000000000000000dead"),
},
Data: w3.B("0x0000000000000000000000000000000000000000000000001111d67bb1bb0000"),
}
from common.Address
to common.Address
value big.Int
)
if err := eventTransfer.DecodeArgs(log, &from, &to, &value); err != nil {
fmt.Printf("Failed to decode event log: %v\n", err)
return
}
fmt.Printf("Transferred %s WETH9 from %s to %s", w3.FromWei(&value, 18), from, to)
// Output:
// Transferred 1.23 WETH9 from 0x000000000000000000000000000000000000c0Fe to 0x000000000000000000000000000000000000dEaD
}
================================================
FILE: func.go
================================================
package w3
import (
"bytes"
"errors"
"fmt"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/crypto"
_abi "github.com/lmittmann/w3/internal/abi"
)
var (
ErrInvalidABI = errors.New("w3: invalid ABI")
ErrArgumentMismatch = errors.New("w3: argument mismatch")
ErrReturnsMismatch = errors.New("w3: returns mismatch")
ErrInvalidType = errors.New("w3: invalid type")
ErrEvmRevert = errors.New("w3: evm reverted")
revertSelector = selector("Error(string)")
outputSuccess = B("0x0000000000000000000000000000000000000000000000000000000000000001")
approveSelector = selector("approve(address,uint256)")
transferSelector = selector("transfer(address,uint256)")
transferFromSelector = selector("transferFrom(address,address,uint256)")
)
// Func represents a Smart Contract function ABI binding.
//
// Func implements the [w3types.Func] interface.
type Func struct {
Signature string // Function signature
Selector [4]byte // 4-byte selector
Args abi.Arguments // Arguments (input)
Returns abi.Arguments // Returns (output)
name string // Function name
}
// NewFunc returns a new Smart Contract function ABI binding from the given
// Solidity function signature and its returns.
//
// The optional tuples parameter accepts struct definitions that can be
// referenced by name in the signature instead of using inline tuple
// definitions. This enables cleaner, more readable function signatures when
// working with complex tuple types.
//
// Examples:
//
// // Without named tuples (inline)
// NewFunc("transfer((address,uint256))", "bool")
//
// // With named tuple
// type Token struct { To common.Address; Amount *big.Int }
// NewFunc("transfer(Token)", "bool", Token{})
//
// An error is returned if the signature or returns parsing fails.
func NewFunc(signature, returns string, tuples ...any) (*Func, error) {
name, args, err := _abi.ParseWithName(signature, tuples...)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrInvalidABI, err)
}
if name == "" {
return nil, fmt.Errorf("%w: missing function name", ErrInvalidABI)
}
returnArgs, err := _abi.Parse(returns, tuples...)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrInvalidABI, err)
}
sig := args.SignatureWithName(name)
return &Func{
Signature: sig,
Selector: selector(sig),
Args: abi.Arguments(args),
Returns: abi.Arguments(returnArgs),
name: name,
}, nil
}
// MustNewFunc is like [NewFunc] but panics if the signature or returns parsing
// fails.
func MustNewFunc(signature, returns string, tuples ...any) *Func {
fn, err := NewFunc(signature, returns, tuples...)
if err != nil {
panic(err)
}
return fn
}
// EncodeArgs ABI-encodes the given args and prepends the Func's 4-byte
// selector.
func (f *Func) EncodeArgs(args ...any) ([]byte, error) {
return _abi.Arguments(f.Args).EncodeWithSelector(f.Selector, args...)
}
// DecodeArgs ABI-decodes the given input to the given args.
func (f *Func) DecodeArgs(input []byte, args ...any) error {
if len(input) < 4 {
return errors.New("w3: insufficient input length")
}
if !bytes.Equal(input[:4], f.Selector[:]) {
return errors.New("w3: input does not match selector")
}
return _abi.Arguments(f.Args).Decode(input[4:], args...)
}
// DecodeReturns ABI-decodes the given output to the given returns.
func (f *Func) DecodeReturns(output []byte, returns ...any) error {
// check the output for a revert reason
if bytes.HasPrefix(output, revertSelector[:]) {
if reason, err := abi.UnpackRevert(output); err != nil {
return err
} else {
return fmt.Errorf("%w: %s", ErrEvmRevert, reason)
}
}
// Gracefully handle uncompliant ERC20 returns
if len(returns) == 1 && len(output) == 0 &&
(f.Selector == approveSelector ||
f.Selector == transferSelector ||
f.Selector == transferFromSelector) {
output = outputSuccess
}
return _abi.Arguments(f.Returns).Decode(output, returns...)
}
// selector returns the 4-byte selector of the given signature.
func selector(signature string) (selector [4]byte) {
copy(selector[:], crypto.Keccak256([]byte(signature)))
return
}
================================================
FILE: func_test.go
================================================
package w3_test
import (
"bytes"
"errors"
"math/big"
"strconv"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/lmittmann/w3"
"github.com/lmittmann/w3/internal"
"github.com/lmittmann/w3/w3types"
)
func TestNewFunc(t *testing.T) {
tests := []struct {
Signature string
Returns string
Tuples []any
WantFunc *w3.Func
}{
{
Signature: "transfer(address,uint256)",
Returns: "bool",
WantFunc: &w3.Func{
Signature: "transfer(address,uint256)",
Selector: [4]byte{0xa9, 0x05, 0x9c, 0xbb},
},
},
{
Signature: "transfer(address recipient, uint256 amount)",
Returns: "bool success",
WantFunc: &w3.Func{
Signature: "transfer(address,uint256)",
Selector: [4]byte{0xa9, 0x05, 0x9c, 0xbb},
},
},
{
Signature: "testTuple(tuple)",
Returns: "bool",
Tuples: []any{tuple{}},
WantFunc: &w3.Func{
Signature: "testTuple((address,uint256))",
Selector: [4]byte{0xa0, 0x54, 0xdf, 0xd5},
},
},
{
Signature: "testTuple(tupleWithTag)",
Returns: "bool",
Tuples: []any{tupleWithTag{}},
WantFunc: &w3.Func{
Signature: "testTuple((address,uint128))",
Selector: [4]byte{0xa8, 0x97, 0xff, 0xb3},
},
},
{
Signature: "testTuple(tupleWithNesting)",
Returns: "bool",
Tuples: []any{tupleWithNesting{}},
WantFunc: &w3.Func{
Signature: "testTuple((address,(address,uint256)))",
Selector: [4]byte{0xff, 0x4c, 0x07, 0xd1},
},
},
}
for i, test := range tests {
t.Run(strconv.Itoa(i), func(t *testing.T) {
gotFunc, err := w3.NewFunc(test.Signature, test.Returns, test.Tuples...)
if err != nil {
t.Fatalf("Failed to create new FUnc: %v", err)
}
if diff := cmp.Diff(test.WantFunc, gotFunc,
cmpopts.IgnoreFields(w3.Func{}, "Args", "Returns", "name"),
); diff != "" {
t.Fatalf("(-want, +got)\n%s", diff)
}
})
}
}
func TestFuncEncodeArgs(t *testing.T) {
tests := []struct {
Func w3types.Func
Args []any
Want []byte
}{
{
Func: w3.MustNewFunc("balanceOf(address who)", "uint256 balance"),
Args: []any{w3.A("0x000000000000000000000000000000000000dEaD")},
Want: w3.B("0x70a08231000000000000000000000000000000000000000000000000000000000000dEaD"),
},
{
Func: w3.MustNewFunc("transfer(address recipient, uint256 amount)", "bool success"),
Args: []any{w3.A("0x000000000000000000000000000000000000dEaD"), big.NewInt(1)},
Want: w3.B("0xa9059cbb000000000000000000000000000000000000000000000000000000000000dEaD0000000000000000000000000000000000000000000000000000000000000001"),
},
{
Func: w3.MustNewFunc("name()", "string"),
Args: []any{},
Want: w3.B("0x06fdde03"),
},
{
Func: w3.MustNewFunc("withdraw(uint256)", ""),
Args: []any{big.NewInt(1)},
Want: w3.B("0x2e1a7d4d0000000000000000000000000000000000000000000000000000000000000001"),
},
{
Func: w3.MustNewFunc("getAmountsOut(uint256,address[])", "uint256[]"),
Args: []any{big.NewInt(1), []common.Address{w3.A("0x1111111111111111111111111111111111111111"), w3.A("0x2222222222222222222222222222222222222222")}},
Want: w3.B("0xd06ca61f00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000011111111111111111111111111111111111111110000000000000000000000002222222222222222222222222222222222222222"),
},
{
Func: w3.MustNewFunc("test((address arg0, uint256 arg1))", ""),
Args: []any{&tuple{
Arg0: w3.A("0x000000000000000000000000000000000000c0Fe"),
Arg1: big.NewInt(42),
}},
Want: w3.B("0xba71720c000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000002a"),
},
{
Func: w3.MustNewFunc("test((address arg0, uint256 arg1))", ""),
Args: []any{&tupleWithWrongOrder{
Arg1: big.NewInt(42),
Arg0: w3.A("0x000000000000000000000000000000000000c0Fe"),
}},
Want: w3.B("0xba71720c000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000002a"),
},
{
Func: w3.MustNewFunc("test((address arg0, uint256 arg1))", ""),
Args: []any{&tupleWithMoreArgs{
Arg0: w3.A("0x000000000000000000000000000000000000c0Fe"),
Arg1: big.NewInt(42),
Arg2: big.NewInt(7),
}},
Want: w3.B("0xba71720c000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000002a"),
},
{
Func: w3.MustNewFunc("test((address arg0, uint256 arg1)[] args)", ""),
Args: []any{
[]tuple{
{Arg0: w3.A("0x1111111111111111111111111111111111111111"), Arg1: big.NewInt(7)},
{Arg0: w3.A("0x2222222222222222222222222222222222222222"), Arg1: big.NewInt(42)},
},
},
Want: w3.B("0xae4f5efa00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000070000000000000000000000002222222222222222222222222222222222222222000000000000000000000000000000000000000000000000000000000000002a"),
},
{
Func: w3.MustNewFunc("test((address arg0, bytes arg1)[] calls)", ""),
Args: []any{
[]tupleWithBytes{
{Arg0: w3.A("0x1111111111111111111111111111111111111111"), Arg1: w3.B("0xc0fe")},
{Arg0: w3.A("0x2222222222222222222222222222222222222222"), Arg1: w3.B("0xdeadbeef")},
},
},
Want: w3.B("0x3a91207700000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002c0fe000000000000000000000000000000000000000000000000000000000000000000000000000000000000222222222222222222222222222222222222222200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000004deadbeef00000000000000000000000000000000000000000000000000000000"),
},
{
Func: w3.MustNewFunc("test(tupleWithBytes[] calls)", "", tupleWithBytes{}),
Args: []any{
[]tupleWithBytes{
{Arg0: w3.A("0x1111111111111111111111111111111111111111"), Arg1: w3.B("0xc0fe")},
{Arg0: w3.A("0x2222222222222222222222222222222222222222"), Arg1: w3.B("0xdeadbeef")},
},
},
Want: w3.B("0x3a91207700000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002c0fe000000000000000000000000000000000000000000000000000000000000000000000000000000000000222222222222222222222222222222222222222200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000004deadbeef00000000000000000000000000000000000000000000000000000000"),
},
{
Func: w3.MustNewFunc("test(uint[])", ""),
Args: []any{
[]*big.Int{big.NewInt(0xdead), big.NewInt(0xbeef)},
},
Want: w3.B("0xca16068400000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000dead000000000000000000000000000000000000000000000000000000000000beef"),
},
{
Func: w3.MustNewFunc("test(uint[2])", ""),
Args: []any{
[2]*big.Int{big.NewInt(0xdead), big.NewInt(0xbeef)},
},
Want: w3.B("0xf1635056000000000000000000000000000000000000000000000000000000000000dead000000000000000000000000000000000000000000000000000000000000beef"),
},
{
Func: w3.MustNewFunc("test(uint64[])", ""),
Args: []any{
[]uint64{0xdead, 0xbeef},
},
Want: w3.B("0xd3469fbd00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000dead000000000000000000000000000000000000000000000000000000000000beef"),
},
{
Func: w3.MustNewFunc("test(uint64[2])", ""),
Args: []any{
[2]uint64{0xdead, 0xbeef},
},
Want: w3.B("0x533d6285000000000000000000000000000000000000000000000000000000000000dead000000000000000000000000000000000000000000000000000000000000beef"),
},
{
Func: w3.MustNewFunc("testTuple(tuple)", "bool", tuple{}),
Args: []any{&tuple{
Arg0: w3.A("0x000000000000000000000000000000000000c0Fe"),
Arg1: big.NewInt(42),
}},
Want: w3.B("0xa054dfd5000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000002a"),
},
{ // https://github.com/lmittmann/w3/issues/35
Func: w3.MustNewFunc("test(((address to)[] recipients) param)", ""),
Args: []any{
&tupleIssue35{Recipients: []struct {
To common.Address
}{
{To: w3.A("0x1111111111111111111111111111111111111111")},
{To: w3.A("0x2222222222222222222222222222222222222222")},
}},
},
Want: w3.B("0xf61d1a2a00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000011111111111111111111111111111111111111110000000000000000000000002222222222222222222222222222222222222222"),
},
}
for i, test := range tests {
t.Run(strconv.Itoa(i), func(t *testing.T) {
encodedInput, err := test.Func.EncodeArgs(test.Args...)
if err != nil {
t.Fatalf("Failed to encode args: %v", err)
}
if !bytes.Equal(test.Want, encodedInput) {
t.Fatalf("(-want, +got)\n- 0x%x\n+ 0x%x", test.Want, encodedInput)
}
})
}
}
func TestFuncDecodeArgs(t *testing.T) {
tests := []struct {
Func w3types.Func
Input []byte
Args []any
WantArgs []any
WantErr error
}{
{
Func: w3.MustNewFunc("test(address)", ""),
Input: w3.B("0xbb29998e000000000000000000000000000000000000000000000000000000000000c0fe"),
Args: []any{new(common.Address)},
WantArgs: []any{w3.APtr("0x000000000000000000000000000000000000c0Fe")},
},
{
Func: w3.MustNewFunc("test(uint256)", ""),
Input: w3.B("0x29e99f07000000000000000000000000000000000000000000000000000000000000002a"),
Args: []any{new(big.Int)},
WantArgs: []any{big.NewInt(42)},
},
{
Func: w3.MustNewFunc("test(bool)", ""),
Input: w3.B("0x36091dff0000000000000000000000000000000000000000000000000000000000000001"),
Args: []any{ptr(false)},
WantArgs: []any{ptr(true)},
},
{
Func: w3.MustNewFunc("test(bytes32)", ""),
Input: w3.B("0x993723210102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"),
Args: []any{&[32]byte{}},
WantArgs: []any{&[32]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}},
},
{
Func: w3.MustNewFunc("test(bytes32)", ""),
Input: w3.B("0x993723210102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"),
Args: []any{new(common.Hash)},
WantArgs: []any{ptr(w3.H("0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"))},
},
{
Func: w3.MustNewFunc("test(bytes)", ""),
Input: w3.B("0x2f570a23000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000030102030000000000000000000000000000000000000000000000000000000000"),
Args: []any{&[]byte{}},
WantArgs: []any{&[]byte{1, 2, 3}},
},
{
Func: w3.MustNewFunc("test((address arg0, uint256 arg1))", ""),
Input: w3.B("0xba71720c000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000002a"),
Args: []any{new(tuple)},
WantArgs: []any{&tuple{
Arg0: w3.A("0x000000000000000000000000000000000000c0Fe"),
Arg1: big.NewInt(42),
}},
},
{
Func: w3.MustNewFunc("test(tuple)", "", tuple{}),
Input: w3.B("0xba71720c000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000002a"),
Args: []any{new(tuple)},
WantArgs: []any{&tuple{
Arg0: w3.A("0x000000000000000000000000000000000000c0Fe"),
Arg1: big.NewInt(42),
}},
},
{
// https://github.com/lmittmann/w3/issues/67
Func: w3.MustNewFunc("test((address, uint256))", ""),
Input: w3.B("0xba71720c000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000002a"),
Args: []any{nil},
WantArgs: []any{nil},
},
{
// https://github.com/lmittmann/w3/issues/67
Func: w3.MustNewFunc("test((address, uint256))", ""),
Input: w3.B("0xba71720c000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000002a"),
Args: []any{new(tuple)},
WantArgs: []any{&tuple{
Arg0: w3.A("0x000000000000000000000000000000000000c0Fe"),
Arg1: big.NewInt(42),
}},
},
{
// https://github.com/lmittmann/w3/issues/67
Func: w3.MustNewFunc("test((address, (address, uint256)))", ""),
Input: w3.B("0x1a68b84c000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000dead000000000000000000000000000000000000000000000000000000000000002a"),
Args: []any{new(tupleNested)},
WantArgs: []any{&tupleNested{
Arg0: w3.A("0x000000000000000000000000000000000000c0Fe"),
Arg1: tuple{
Arg0: w3.A("0x000000000000000000000000000000000000dEaD"),
Arg1: big.NewInt(42),
},
}},
},
{
Func: w3.MustNewFunc("test((address arg0, uint256 arg1))", ""),
Input: w3.B("0xba71720c000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000002a"),
Args: []any{new(tupleWithWrongOrder)},
WantArgs: []any{&tupleWithWrongOrder{
Arg1: big.NewInt(42),
Arg0: w3.A("0x000000000000000000000000000000000000c0Fe"),
}},
},
{
Func: w3.MustNewFunc("test((address arg0, uint256 arg1))", ""),
Input: w3.B("0xba71720c000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000002a"),
Args: []any{new(tupleWithMoreArgs)},
WantArgs: []any{&tupleWithMoreArgs{
Arg0: w3.A("0x000000000000000000000000000000000000c0Fe"),
Arg1: big.NewInt(42),
}},
},
{ // https://github.com/lmittmann/w3/issues/22
Func: w3.MustNewFunc("transfer(address recipient, uint256 amount)", "bool success"),
Input: w3.B("0x"),
Args: []any{new(common.Address), new(big.Int)},
WantErr: errors.New("w3: insufficient input length"),
},
{
Func: w3.MustNewFunc("test((address arg0, uint256 arg1))", ""),
Input: w3.B("0xba71720c000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000002a"),
Args: []any{new(tupleWithUnexportedProperty)},
WantArgs: []any{&tupleWithUnexportedProperty{
Arg1: big.NewInt(42),
}},
},
{
Func: w3.MustNewFunc("test((address arg0, bytes arg1)[] calls)", ""),
Input: w3.B("0x3a91207700000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002c0fe000000000000000000000000000000000000000000000000000000000000000000000000000000000000222222222222222222222222222222222222222200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000004deadbeef00000000000000000000000000000000000000000000000000000000"),
Args: []any{&[]*tupleWithBytes{}},
WantArgs: []any{
&[]*tupleWithBytes{
{Arg0: w3.A("0x1111111111111111111111111111111111111111"), Arg1: w3.B("0xc0fe")},
{Arg0: w3.A("0x2222222222222222222222222222222222222222"), Arg1: w3.B("0xdeadbeef")},
},
},
},
{
Func: w3.MustNewFunc("test(uint[])", ""),
Input: w3.B("0xca16068400000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000dead000000000000000000000000000000000000000000000000000000000000beef"),
Args: []any{new([]*big.Int)},
WantArgs: []any{
&[]*big.Int{big.NewInt(0xdead), big.NewInt(0xbeef)},
},
},
{
Func: w3.MustNewFunc("test(uint[2])", ""),
Input: w3.B("0xf1635056000000000000000000000000000000000000000000000000000000000000dead000000000000000000000000000000000000000000000000000000000000beef"),
Args: []any{new([2]*big.Int)},
WantArgs: []any{
&[2]*big.Int{big.NewInt(0xdead), big.NewInt(0xbeef)},
},
},
{
Func: w3.MustNewFunc("test(uint64[])", ""),
Input: w3.B("0xd3469fbd00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000dead000000000000000000000000000000000000000000000000000000000000beef"),
Args: []any{new([]uint64)},
WantArgs: []any{
&[]uint64{0xdead, 0xbeef},
},
},
{
Func: w3.MustNewFunc("test(uint64[2])", ""),
Input: w3.B("0x533d6285000000000000000000000000000000000000000000000000000000000000dead000000000000000000000000000000000000000000000000000000000000beef"),
Args: []any{new([2]uint64)},
WantArgs: []any{
&[2]uint64{0xdead, 0xbeef},
},
},
{
Func: w3.MustNewFunc("testTuple(tuple)", "bool", tuple{}),
Input: w3.B("0xa054dfd5000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000002a"),
Args: []any{new(tuple)},
WantArgs: []any{&tuple{
Arg0: w3.A("0x000000000000000000000000000000000000c0Fe"),
Arg1: big.NewInt(42),
}},
},
{ // https://github.com/lmittmann/w3/issues/35
Func: w3.MustNewFunc("test(((address to)[] recipients) param)", ""),
Input: w3.B("0xf61d1a2a00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000011111111111111111111111111111111111111110000000000000000000000002222222222222222222222222222222222222222"),
Args: []any{new(tupleIssue35)},
WantArgs: []any{
&tupleIssue35{Recipients: []struct {
To common.Address
}{
{To: w3.A("0x1111111111111111111111111111111111111111")},
{To: w3.A("0x2222222222222222222222222222222222222222")},
}},
},
},
{
Func: w3.MustNewFunc("test(address)", ""),
Input: w3.B("0xffffffff000000000000000000000000000000000000000000000000000000000000c0fe"),
Args: []any{new(common.Address)},
WantErr: errors.New("w3: input does not match selector"),
},
}
for i, test := range tests {
t.Run(strconv.Itoa(i), func(t *testing.T) {
err := test.Func.DecodeArgs(test.Input, test.Args...)
if diff := cmp.Diff(test.WantErr, err, internal.EquateErrors()); diff != "" {
t.Fatalf("Err: (-want, +got)\n%s", diff)
}
if err != nil {
return
}
if diff := cmp.Diff(test.WantArgs, test.Args,
cmp.AllowUnexported(big.Int{}, tupleWithUnexportedProperty{}),
); diff != "" {
t.Fatalf("Args: (-want, +got)\n%s", diff)
}
})
}
}
func TestFuncDecodeReturns(t *testing.T) {
tests := []struct {
Func w3types.Func
Output []byte
Returns []any
WantReturns []any
}{
{
Func: w3.MustNewFunc("test()", "address"),
Output: w3.B("0x000000000000000000000000000000000000000000000000000000000000c0fe"),
Returns: []any{new(common.Address)},
WantReturns: []any{w3.APtr("0x000000000000000000000000000000000000c0Fe")},
},
{
Func: w3.MustNewFunc("test()", "uint256"),
Output: w3.B("0x000000000000000000000000000000000000000000000000000000000000002a"),
Returns: []any{new(big.Int)},
WantReturns: []any{big.NewInt(42)},
},
{
Func: w3.MustNewFunc("test()", "bool"),
Output: w3.B("0x0000000000000000000000000000000000000000000000000000000000000001"),
Returns: []any{ptr(false)},
WantReturns: []any{ptr(true)},
},
{
Func: w3.MustNewFunc("test()", "bytes32"),
Output: w3.B("0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"),
Returns: []any{&[32]byte{}},
WantReturns: []any{&[32]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}},
},
{
Func: w3.MustNewFunc("test()", "bytes32"),
Output: w3.B("0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"),
Returns: []any{new(common.Hash)},
WantReturns: []any{ptr(w3.H("0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"))},
},
{
Func: w3.MustNewFunc("test()", "bytes"),
Output: w3.B("0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000030102030000000000000000000000000000000000000000000000000000000000"),
Returns: []any{&[]byte{}},
WantReturns: []any{&[]byte{1, 2, 3}},
},
{ // https://github.com/lmittmann/w3/issues/25
Func: w3.MustNewFunc("test()", "(address arg0, uint256 arg1)"),
Output: w3.B("0x000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000002a"),
Returns: []any{new(tuple)},
WantReturns: []any{&tuple{
Arg0: w3.A("0x000000000000000000000000000000000000c0Fe"),
Arg1: big.NewInt(42),
}},
},
{
Func: w3.MustNewFunc("test()", "tuple", tuple{}),
Output: w3.B("0x000000000000000000000000000000000000000000000000000000000000c0fe000000000000000000000000000000000000000000000000000000000000002a"),
Returns: []any{new(tuple)},
WantReturns: []any{&tuple{
Arg0: w3.A("0x000000000000000000000000000000000000c0Fe"),
Arg1: big.NewInt(42),
}},
},
}
for i, test := range tests {
t.Run(strconv.Itoa(i), func(t *testing.T) {
if err := test.Func.DecodeReturns(test.Output, test.Returns...); err != nil {
t.Fatalf("Failed to decode returns: %v", err)
}
if diff := cmp.Diff(test.WantReturns, test.Returns, cmp.AllowUnexported(big.Int{})); diff != "" {
t.Fatalf("(-want, +got)\n%s", diff)
}
})
}
}
func ptr[T any](v T) *T { return &v }
type tuple struct {
Arg0 common.Address
Arg1 *big.Int
}
type tupleWithTag struct {
Arg0 common.Address `abitype:"address"`
Arg1 *big.Int `abitype:"uint128"`
}
type tupleWithNesting struct {
Arg0 common.Address
Arg1 tuple
}
type tupleWithBytes struct {
Arg0 common.Address
Arg1 []byte
}
type tupleWithUnexportedProperty struct {
//lint:ignore U1000 ignore unused field
arg0 common.Address
Arg1 *big.Int
}
type tupleWithWrongOrder struct {
Arg1 *big.Int
Arg0 common.Address
}
type tupleWithMoreArgs struct {
Arg0 common.Address
Arg1 *big.Int
Arg2 *big.Int // Arg that is missing in func signature
}
type tupleIssue35 struct {
Recipients []struct {
To common.Address
}
}
type tupleNested struct {
Arg0 common.Address
Arg1 tuple
}
func BenchmarkFuncEncode(b *testing.B) {
var (
funcSwap = w3.MustNewFunc("swap(uint amount0Out, uint amount1Out, address to, bytes data)", "")
amount0Out = big.NewInt(1000000000000000000) // 1 ETH
amount1Out = big.NewInt(0) // 0 token
to = w3.A("0x000000000000000000000000000000000000c0Fe")
data = []byte{}
)
b.ReportAllocs()
b.ResetTimer()
for range b.N {
funcSwap.EncodeArgs(amount0Out, amount1Out, to, data)
}
}
================================================
FILE: go.mod
================================================
module github.com/lmittmann/w3
go 1.25.0
require (
github.com/charmbracelet/lipgloss v1.1.0
github.com/ethereum/go-ethereum v1.17.1
github.com/gofrs/flock v0.13.0
github.com/google/go-cmp v0.7.0
github.com/holiman/uint256 v1.3.2
golang.org/x/time v0.15.0
)
require (
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 // indirect
github.com/StackExchange/wmi v1.2.1 // indirect
github.com/VictoriaMetrics/fastcache v1.13.0 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/bits-and-blooms/bitset v1.20.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
github.com/charmbracelet/x/ansi v0.8.0 // indirect
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
github.com/charmbracelet/x/term v0.2.1 // indirect
github.com/consensys/gnark-crypto v0.18.1 // indirect
github.com/crate-crypto/go-eth-kzg v1.4.0 // indirect
github.com/deckarep/golang-set/v2 v2.6.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
github.com/emicklei/dot v1.6.2 // indirect
github.com/ethereum/c-kzg-4844/v2 v2.1.6 // indirect
github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab // indirect
github.com/ferranbt/fastssz v0.1.4 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/golang/snappy v1.0.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mitchellh/mapstructure v1.4.1 // indirect
github.com/muesli/termenv v0.16.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
github.com/supranational/blst v0.3.16 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/otel v1.39.0 // indirect
go.opentelemetry.io/otel/metric v1.39.0 // indirect
go.opentelemetry.io/otel/trace v1.39.0 // indirect
golang.org/x/crypto v0.44.0 // indirect
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect
golang.org/x/sync v0.18.0 // indirect
golang.org/x/sys v0.39.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
================================================
FILE: go.sum
================================================
github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=
github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 h1:1zYrtlhrZ6/b6SAjLSfKzWtdgqK0U+HtH/VcBWh1BaU=
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI=
github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA=
github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8=
github.com/VictoriaMetrics/fastcache v1.13.0 h1:AW4mheMR5Vd9FkAPUv+NH6Nhw+fmbTMGMsNAoA/+4G0=
github.com/VictoriaMetrics/fastcache v1.13.0/go.mod h1:hHXhl4DA2fTL2HTZDJFXWgW0LNjo6B+4aj2Wmng3TjU=
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8=
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bits-and-blooms/bitset v1.20.0 h1:2F+rfL86jE2d/bmw7OhqUg2Sj/1rURkBn3MdfoPyRVU=
github.com/bits-and-blooms/bitset v1.20.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk=
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE=
github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q=
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8=
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I=
github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8=
github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/esnpM7Geqxka4WSqI1SZc7sMJFd3y4=
github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M=
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE=
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs=
github.com/cockroachdb/pebble v1.1.5 h1:5AAWCBWbat0uE0blr8qzufZP5tBjkRyy/jWe1QWLnvw=
github.com/cockroachdb/pebble v1.1.5/go.mod h1:17wO9el1YEigxkP/YtV8NtCivQDgoCyBg5c4VR/eOWo=
github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30=
github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo=
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ=
github.com/consensys/gnark-crypto v0.18.1 h1:RyLV6UhPRoYYzaFnPQA4qK3DyuDgkTgskDdoGqFt3fI=
github.com/consensys/gnark-crypto v0.18.1/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx8ubaYfDROyp2Z8c=
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/crate-crypto/go-eth-kzg v1.4.0 h1:WzDGjHk4gFg6YzV0rJOAsTK4z3Qkz5jd4RE3DAvPFkg=
github.com/crate-crypto/go-eth-kzg v1.4.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dchest/siphash v1.2.3 h1:QXwFc8cFOR2dSa/gE6o/HokBMWtLUaNDVd+22aKHeEA=
github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc=
github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM=
github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
github.com/emicklei/dot v1.6.2 h1:08GN+DD79cy/tzN6uLCT84+2Wk9u+wvqP+Hkx/dIR8A=
github.com/emicklei/dot v1.6.2/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s=
github.com/ethereum/c-kzg-4844/v2 v2.1.6 h1:xQymkKCT5E2Jiaoqf3v4wsNgjZLY0lRSkZn27fRjSls=
github.com/ethereum/c-kzg-4844/v2 v2.1.6/go.mod h1:8HMkUZ5JRv4hpw/XUrYWSQNAUzhHMg2UDb/U+5m+XNw=
github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab h1:rvv6MJhy07IMfEKuARQ9TKojGqLVNxQajaXEp/BoqSk=
github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab/go.mod h1:IuLm4IsPipXKF7CW5Lzf68PIbZ5yl7FFd74l/E0o9A8=
github.com/ethereum/go-ethereum v1.17.1 h1:IjlQDjgxg2uL+GzPRkygGULPMLzcYWncEI7wbaizvho=
github.com/ethereum/go-ethereum v1.17.1/go.mod h1:7UWOVHL7K3b8RfVRea022btnzLCaanwHtBuH1jUCH/I=
github.com/ferranbt/fastssz v0.1.4 h1:OCDB+dYDEQDvAgtAGnTSidK1Pe2tW3nFV40XyMkTeDY=
github.com/ferranbt/fastssz v0.1.4/go.mod h1:Ea3+oeoRGGLGm5shYAeDgu6PGUlcvQhE2fILyD9+tGg=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps=
github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw=
github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grafana/pyroscope-go v1.2.7 h1:VWBBlqxjyR0Cwk2W6UrE8CdcdD80GOFNutj0Kb1T8ac=
github.com/grafana/pyroscope-go v1.2.7/go.mod h1:o/bpSLiJYYP6HQtvcoVKiE9s5RiNgjYTj1DhiddP2Pc=
github.com/grafana/pyroscope-go/godeltaprof v0.1.9 h1:c1Us8i6eSmkW+Ez05d3co8kasnuOY813tbMN8i/a3Og=
github.com/grafana/pyroscope-go/godeltaprof v0.1.9/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU=
github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE=
github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0=
github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db h1:IZUYC/xb3giYwBLMnr8d0TGTzPKFGNTCGgGLoyeX330=
github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db/go.mod h1:xTEYN9KCHxuYHs+NmrmzFcnvHMzLLNiGFafCb1n3Mfg=
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA=
github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4=
github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A=
github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4=
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8=
github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s=
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
github.com/pion/stun/v2 v2.0.0 h1:A5+wXKLAypxQri59+tmQKVs7+l6mMM+3d+eER9ifRU0=
github.com/pion/stun/v2 v2.0.0/go.mod h1:22qRSh08fSEttYUmJZGlriq9+03jtVmXNODgLccj8GQ=
github.com/pion/transport/v2 v2.2.1 h1:7qYnCBlpgSJNYMbLCKuSY9KbQdBFoETvPNETv0y4N7c=
github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g=
github.com/pion/transport/v3 v3.0.1 h1:gDTlPJwROfSfz6QfSi0ZmeCSkFcnWWiiR9ES0ouANiM=
github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.15.0 h1:5fCgGYogn0hFdhyhLbw7hEsWxufKtY9klyvdNfFlFhM=
github.com/prometheus/client_golang v1.15.0/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk=
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
github.com/prysmaticlabs/gohashtree v0.0.4-beta h1:H/EbCuXPeTV3lpKeXGPpEV9gsUpkqOOVnWapUyeWro4=
github.com/prysmaticlabs/gohashtree v0.0.4-beta/go.mod h1:BFdtALS+Ffhg3lGQIHv9HDWuHS8cTvHZzrHWxwOtGOs=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU=
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/supranational/blst v0.3.16 h1:bTDadT+3fK497EvLdWRQEjiGnUtzJ7jjIUMF0jqwYhE=
github.com/supranational/blst v0.3.16/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w=
github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU=
golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ=
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
================================================
FILE: internal/abi/arguments.go
================================================
package abi
import (
"fmt"
"strconv"
"strings"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/lmittmann/w3/internal/crypto"
)
// Arguments represents a slice of [abi.Argument]'s.
type Arguments []abi.Argument
func (a Arguments) Signature() string {
if len(a) <= 0 {
return ""
}
fields := make([]string, len(a))
for i, arg := range a {
fields[i] = typeToString(&arg.Type)
}
return strings.Join(fields, ",")
}
func (a Arguments) SignatureWithName(name string) string {
return name + "(" + a.Signature() + ")"
}
// Encode ABI-encodes the given arguments args.
func (a Arguments) Encode(args ...any) ([]byte, error) {
data, err := abi.Arguments(a).PackValues(args)
if err != nil {
return nil, err
}
return data, nil
}
// EncodeWithSelector ABI-encodes the given arguments args prepended by the
// given selector.
func (a Arguments) EncodeWithSelector(selector [4]byte, args ...any) ([]byte, error) {
data, err := a.Encode(args...)
if err != nil {
return nil, err
}
data = append(selector[:], data...)
return data, nil
}
// EncodeWithSignature ABI-encodes the given arguments args prepended by the
// first 4 bytes of the hash of the given signature.
func (a Arguments) EncodeWithSignature(signature string, args ...any) ([]byte, error) {
var selector [4]byte
copy(selector[:], crypto.Keccak256([]byte(signature))[:4])
return a.EncodeWithSelector(selector, args...)
}
// Decode ABI-decodes the given data to the given arguments args.
func (a Arguments) Decode(data []byte, args ...any) error {
values, err := abi.Arguments(a).UnpackValues(data)
if err != nil {
return err
}
for i, arg := range args {
// discard if arg is nil
if arg == nil {
continue
}
if err := Copy(arg, values[i]); err != nil {
return err
}
}
return nil
}
// typeToString returns the string representation of a [abi.Type].
func typeToString(t *abi.Type) string {
switch t.T {
case abi.IntTy:
return "int" + strconv.Itoa(t.Size)
case abi.UintTy:
return "uint" + strconv.Itoa(t.Size)
case abi.BoolTy:
return "bool"
case abi.StringTy:
return "string"
case abi.SliceTy:
return typeToString(t.Elem) + "[]"
case abi.ArrayTy:
return typeToString(t.Elem) + "[" + strconv.Itoa(t.Size) + "]"
case abi.TupleTy:
fields := make([]string, len(t.TupleElems))
for i, elem := range t.TupleElems {
fields[i] = typeToString(elem)
}
return "(" + strings.Join(fields, ",") + ")"
case abi.AddressTy:
return "address"
case abi.FixedBytesTy:
return "bytes" + strconv.Itoa(t.Size)
case abi.BytesTy:
return "bytes"
case abi.HashTy:
return "hash"
default:
panic(fmt.Sprintf("unsupported type %v", t))
}
}
================================================
FILE: internal/abi/arguments_test.go
================================================
package abi
import (
"bytes"
"math/big"
"reflect"
"strconv"
"testing"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/google/go-cmp/cmp"
)
func TestSignature(t *testing.T) {
tests := []struct {
Args Arguments
WantSignature string
}{
{
Args: Arguments{},
WantSignature: "",
},
{
Args: Arguments{{Type: typeUint256}},
WantSignature: "uint256",
},
{
Args: Arguments{{Type: abi.Type{Elem: &typeUint256, T: abi.SliceTy}}},
WantSignature: "uint256[]",
},
{
Args: Arguments{{Type: abi.Type{Elem: &typeUint256, T: abi.ArrayTy, Size: 3}}},
WantSignature: "uint256[3]",
},
{
Args: Arguments{{
Type: abi.Type{
T: abi.TupleTy,
TupleElems: []*abi.Type{&typeUint256},
TupleRawNames: []string{"arg0"},
},
}},
WantSignature: "(uint256)",
},
}
for i, test := range tests {
t.Run(strconv.Itoa(i), func(t *testing.T) {
gotSignature := test.Args.Signature()
if test.WantSignature != gotSignature {
t.Fatalf("want %q, got %q", test.WantSignature, gotSignature)
}
})
}
}
func TestSignatureWithName(t *testing.T) {
tests := []struct {
Arguments Arguments
Name string
WantSignature string
}{
{
Arguments: Arguments{},
Name: "func",
WantSignature: "func()",
},
{
Arguments: Arguments{{Type: typeUint256}},
Name: "func",
WantSignature: "func(uint256)",
},
}
for i, test := range tests {
t.Run(strconv.Itoa(i), func(t *testing.T) {
gotSignature := test.Arguments.SignatureWithName(test.Name)
if test.WantSignature != gotSignature {
t.Fatalf("want %q, got %q", test.WantSignature, gotSignature)
}
})
}
}
func TestEncode(t *testing.T) {
tests := []struct {
Arguments Arguments
Args []any
WantData []byte
}{
{
Arguments: Arguments{{Type: typeUint256}},
Args: []any{big.NewInt(1)},
WantData: common.FromHex("0x0000000000000000000000000000000000000000000000000000000000000001"),
},
}
for i, test := range tests {
t.Run(strconv.Itoa(i), func(t *testing.T) {
gotData, err := test.Arguments.Encode(test.Args...)
if err != nil {
t.Fatalf("Failed to encode args: %v", err)
}
if !bytes.Equal(test.WantData, gotData) {
t.Fatalf("\nwant 0x%x\ngot 0x%x", test.WantData, gotData)
}
})
}
}
func TestEncodeWithSelector(t *testing.T) {
tests := []struct {
Arguments Arguments
Selector [4]byte
Args []any
WantData []byte
}{
{
Arguments: Arguments{{Type: typeUint256}},
Selector: [4]byte{0x12, 0x34, 0x56, 0x78},
Args: []any{big.NewInt(1)},
WantData: common.FromHex("0x123456780000000000000000000000000000000000000000000000000000000000000001"),
},
}
for i, test := range tests {
t.Run(strconv.Itoa(i), func(t *testing.T) {
gotData, err := test.Arguments.EncodeWithSelector(test.Selector, test.Args...)
if err != nil {
t.Fatalf("Failed to encode args: %v", err)
}
if !bytes.Equal(test.WantData, gotData) {
t.Fatalf("\nwant 0x%x\ngot 0x%x", test.WantData, gotData)
}
})
}
}
func TestEncodeWithSignature(t *testing.T) {
tests := []struct {
Arguments Arguments
Args []any
Signature string
WantData []byte
}{
{
Arguments: Arguments{{Type: typeUint256}},
Args: []any{big.NewInt(1)},
Signature: "func(uint256)",
WantData: common.FromHex("0x7f98a45e0000000000000000000000000000000000000000000000000000000000000001"),
},
}
for i, test := range tests {
t.Run(strconv.Itoa(i), func(t *testing.T) {
gotData, err := test.Arguments.EncodeWithSignature(test.Signature, test.Args...)
if err != nil {
t.Fatalf("Failed to encode args: %v", err)
}
if !bytes.Equal(test.WantData, gotData) {
t.Fatalf("\nwant 0x%x\ngot 0x%x", test.WantData, gotData)
}
})
}
}
func TestDecode(t *testing.T) {
type tuple struct {
A bool
B *big.Int
}
var (
dataUintBool = common.FromHex("0x0000000000000000000000000000000000000000000000000000000000000001")
argsUint = Arguments{{Type: typeUint256}}
argsBool = Arguments{{Type: typeBool}}
dataTuple = common.FromHex("0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000007")
argsTuple = Arguments{{Type: abi.Type{
T: abi.TupleTy,
TupleElems: []*abi.Type{&typeBool, &typeUint256},
TupleRawNames: []string{"A", "_a"},
TupleType: reflect.TypeFor[struct {
A bool `abi:"a"`
B *big.Int `abi:"b"`
}](),
}}}
dataBytes2 = common.FromHex("0xc0fe000000000000000000000000000000000000000000000000000000000000")
argsBytes2 = Arguments{{Type: abi.Type{T: abi.FixedBytesTy, Size: 2}}}
dataSlice = common.FromHex("0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000007")
argsSlice = Arguments{{Type: abi.Type{T: abi.SliceTy, Size: 1, Elem: &typeUint256}}}
)
t.Run("set-ptr", func(t *testing.T) {
var arg big.Int
err := argsUint.Decode(dataUintBool, &arg)
if err != nil {
t.Fatalf("Failed to decode args: %v", err)
}
if want := big.NewInt(1); arg.Cmp(want) != 0 {
t.Fatalf("want %v, got %v", want, arg)
}
})
t.Run("set-ptr-of-ptr", func(t *testing.T) {
var arg *big.Int
err := argsUint.Decode(dataUintBool, &arg)
if err != nil {
t.Fatalf("Failed to decode args: %v", err)
}
if want := big.NewInt(1); arg.Cmp(want) != 0 {
t.Fatalf("want %v, got %v", want, arg)
}
})
t.Run("nil-val", func(t *testing.T) {
var arg *big.Int
err := argsUint.Decode(dataUintBool, arg)
if want := "abi: decode nil *big.Int"; err == nil || want != err.Error() {
t.Fatalf("want %v, got %v", want, err)
}
})
t.Run("nil", func(t *testing.T) {
if err := argsUint.Decode(dataUintBool, nil); err != nil {
t.Fatalf("want nil, got %v", err)
}
})
t.Run("non-ptr", func(t *testing.T) {
var arg bool
err := argsBool.Decode(dataUintBool, arg)
if want := "abi: decode non-pointer bool"; err == nil || want != err.Error() {
t.Fatalf("want %v, got %v", want, err)
}
})
t.Run("set-bool-ptr", func(t *testing.T) {
var arg bool
err := argsBool.Decode(dataUintBool, &arg)
if err != nil {
t.Fatalf("Failed to decode args: %v", err)
}
if want := true; arg != want {
t.Fatalf("want %v, got %v", want, arg)
}
})
t.Run("set-bool-ptr-of-ptr", func(t *testing.T) {
var arg *bool
err := argsBool.Decode(dataUintBool, &arg)
if err != nil {
t.Fatalf("Failed to decode args: %v", err)
}
if want := true; *arg != want {
t.Fatalf("want %v, got %v", want, arg)
}
})
t.Run("set-bytes2", func(t *testing.T) {
var arg [2]byte
err := argsBytes2.Decode(dataBytes2, &arg)
if err != nil {
t.Fatalf("Failed to decode args: %v", err)
}
want := [2]byte{0xc0, 0xfe}
if diff := cmp.Diff(want, arg); diff != "" {
t.Fatalf("(-want, +got)\n%s", diff)
}
})
t.Run("set-tuple-ptr", func(t *testing.T) {
var arg tuple
err := argsTuple.Decode(dataTuple, &arg)
if err != nil {
t.Fatalf("Failed to decode args: %v", err)
}
want := tuple{A: true, B: big.NewInt(7)}
if diff := cmp.Diff(want, arg, cmp.AllowUnexported(big.Int{})); diff != "" {
t.Fatalf("(-want, +got)\n%s", diff)
}
})
t.Run("set-tuple-ptr-of-ptr", func(t *testing.T) {
var arg *tuple
err := argsTuple.Decode(dataTuple, &arg)
if err != nil {
t.Fatalf("Failed to decode args: %v", err)
}
want := &tuple{A: true, B: big.NewInt(7)}
if diff := cmp.Diff(want, arg, cmp.AllowUnexported(big.Int{})); diff != "" {
t.Fatalf("(-want, +got)\n%s", diff)
}
})
t.Run("set-slice", func(t *testing.T) {
var arg []*big.Int
err := argsSlice.Decode(dataSlice, &arg)
if err != nil {
t.Fatalf("Failed to decode args: %v", err)
}
want := []*big.Int{big.NewInt(7)}
if diff := cmp.Diff(want, arg, cmp.AllowUnexported(big.Int{})); diff != "" {
t.Fatalf("(-want, +got)\n%s", diff)
}
})
}
func TestTypeToString(t *testing.T) {
tests := []struct {
Type *abi.Type
Want string
}{
{Type: &abi.Type{T: abi.BoolTy}, Want: "bool"},
{Type: &abi.Type{T: abi.SliceTy, Elem: &abi.Type{T: abi.BoolTy}}, Want: "bool[]"},
{Type: &abi.Type{Size: 2, T: abi.ArrayTy, Elem: &abi.Type{T: abi.BoolTy}}, Want: "bool[2]"},
{Type: &abi.Type{T: abi.SliceTy, Elem: &abi.Type{T: abi.ArrayTy, Size: 2, Elem: &abi.Type{T: abi.BoolTy}}}, Want: "bool[2][]"},
{Type: &abi.Type{T: abi.SliceTy, Elem: &abi.Type{T: abi.SliceTy, Elem: &abi.Type{T: abi.BoolTy}}}, Want: "bool[][]"},
{Type: &abi.Type{T: abi.ArrayTy, Size: 2, Elem: &abi.Type{T: abi.SliceTy, Elem: &abi.Type{T: abi.BoolTy}}}, Want: "bool[][2]"},
{Type: &abi.Type{T: abi.ArrayTy, Size: 2, Elem: &abi.Type{T: abi.ArrayTy, Size: 2, Elem: &abi.Type{T: abi.BoolTy}}}, Want: "bool[2][2]"},
{Type: &abi.Type{T: abi.ArrayTy, Size: 2, Elem: &abi.Type{T: abi.SliceTy, Elem: &abi.Type{T: abi.ArrayTy, Size: 2, Elem: &abi.Type{T: abi.BoolTy}}}}, Want: "bool[2][][2]"},
{Type: &abi.Type{T: abi.ArrayTy, Size: 2, Elem: &abi.Type{T: abi.ArrayTy, Size: 2, Elem: &abi.Type{T: abi.ArrayTy, Size: 2, Elem: &abi.Type{T: abi.BoolTy}}}}, Want: "bool[2][2][2]"},
{Type: &abi.Type{T: abi.SliceTy, Elem: &abi.Type{T: abi.SliceTy, Elem: &abi.Type{T: abi.SliceTy, Elem: &abi.Type{T: abi.BoolTy}}}}, Want: "bool[][][]"},
{Type: &abi.Type{T: abi.SliceTy, Elem: &abi.Type{T: abi.ArrayTy, Size: 2, Elem: &abi.Type{T: abi.SliceTy, Elem: &abi.Type{T: abi.BoolTy}}}}, Want: "bool[][2][]"},
{Type: &abi.Type{Size: 8, T: abi.IntTy}, Want: "int8"},
{Type: &abi.Type{Size: 16, T: abi.IntTy}, Want: "int16"},
{Type: &abi.Type{Size: 32, T: abi.IntTy}, Want: "int32"},
{Type: &abi.Type{Size: 64, T: abi.IntTy}, Want: "int64"},
{Type: &abi.Type{Size: 256, T: abi.IntTy}, Want: "int256"},
{Type: &abi.Type{T: abi.SliceTy, Elem: &abi.Type{Size: 8, T: abi.IntTy}}, Want: "int8[]"},
{Type: &abi.Type{T: abi.ArrayTy, Size: 2, Elem: &abi.Type{Size: 8, T: abi.IntTy}}, Want: "int8[2]"},
{Type: &abi.Type{T: abi.SliceTy, Elem: &abi.Type{Size: 16, T: abi.IntTy}}, Want: "int16[]"},
{Type: &abi.Type{Size: 2, T: abi.ArrayTy, Elem: &abi.Type{Size: 16, T: abi.IntTy}}, Want: "int16[2]"},
{Type: &abi.Type{T: abi.SliceTy, Elem: &abi.Type{Size: 32, T: abi.IntTy}}, Want: "int32[]"},
{Type: &abi.Type{T: abi.ArrayTy, Size: 2, Elem: &abi.Type{Size: 32, T: abi.IntTy}}, Want: "int32[2]"},
{Type: &abi.Type{T: abi.SliceTy, Elem: &abi.Type{Size: 64, T: abi.IntTy}}, Want: "int64[]"},
{Type: &abi.Type{T: abi.ArrayTy, Size: 2, Elem: &abi.Type{Size: 64, T: abi.IntTy}}, Want: "int64[2]"},
{Type: &abi.Type{T: abi.SliceTy, Elem: &abi.Type{Size: 256, T: abi.IntTy}}, Want: "int256[]"},
{Type: &abi.Type{T: abi.ArrayTy, Size: 2, Elem: &abi.Type{Size: 256, T: abi.IntTy}}, Want: "int256[2]"},
{Type: &abi.Type{Size: 8, T: abi.UintTy}, Want: "uint8"},
{Type: &abi.Type{Size: 16, T: abi.UintTy}, Want: "uint16"},
{Type: &abi.Type{Size: 32, T: abi.UintTy}, Want: "uint32"},
{Type: &abi.Type{Size: 64, T: abi.UintTy}, Want: "uint64"},
{Type: &abi.Type{Size: 256, T: abi.UintTy}, Want: "uint256"},
{Type: &abi.Type{T: abi.SliceTy, Elem: &abi.Type{Size: 8, T: abi.UintTy}}, Want: "uint8[]"},
{Type: &abi.Type{T: abi.ArrayTy, Size: 2, Elem: &abi.Type{Size: 8, T: abi.UintTy}}, Want: "uint8[2]"},
{Type: &abi.Type{T: abi.SliceTy, Elem: &abi.Type{Size: 16, T: abi.UintTy}}, Want: "uint16[]"},
{Type: &abi.Type{T: abi.ArrayTy, Size: 2, Elem: &abi.Type{Size: 16, T: abi.UintTy}}, Want: "uint16[2]"},
{Type: &abi.Type{T: abi.SliceTy, Elem: &abi.Type{Size: 32, T: abi.UintTy}}, Want: "uint32[]"},
{Type: &abi.Type{T: abi.ArrayTy, Size: 2, Elem: &abi.Type{Size: 32, T: abi.UintTy}}, Want: "uint32[2]"},
{Type: &abi.Type{T: abi.SliceTy, Elem: &abi.Type{Size: 64, T: abi.UintTy}}, Want: "uint64[]"},
{Type: &abi.Type{T: abi.ArrayTy, Size: 2, Elem: &abi.Type{Size: 64, T: abi.UintTy}}, Want: "uint64[2]"},
{Type: &abi.Type{T: abi.SliceTy, Elem: &abi.Type{Size: 256, T: abi.UintTy}}, Want: "uint256[]"},
{Type: &abi.Type{T: abi.ArrayTy, Size: 2, Elem: &abi.Type{Size: 256, T: abi.UintTy}}, Want: "uint256[2]"},
{Type: &abi.Type{T: abi.FixedBytesTy, Size: 32}, Want: "bytes32"},
{Type: &abi.Type{T: abi.SliceTy, Elem: &abi.Type{T: abi.BytesTy}}, Want: "bytes[]"},
{Type: &abi.Type{T: abi.ArrayTy, Size: 2, Elem: &abi.Type{T: abi.BytesTy}}, Want: "bytes[2]"},
{Type: &abi.Type{T: abi.SliceTy, Elem: &abi.Type{T: abi.FixedBytesTy, Size: 32}}, Want: "bytes32[]"},
{Type: &abi.Type{T: abi.ArrayTy, Size: 2, Elem: &abi.Type{T: abi.FixedBytesTy, Size: 32}}, Want: "bytes32[2]"},
{Type: &abi.Type{T: abi.HashTy, Size: 20}, Want: "hash"},
{Type: &abi.Type{T: abi.StringTy}, Want: "string"},
{Type: &abi.Type{T: abi.SliceTy, Elem: &abi.Type{T: abi.StringTy}}, Want: "string[]"},
{Type: &abi.Type{T: abi.ArrayTy, Size: 2, Elem: &abi.Type{T: abi.StringTy}}, Want: "string[2]"},
{Type: &abi.Type{Size: 20, T: abi.AddressTy}, Want: "address"},
{Type: &abi.Type{T: abi.SliceTy, Elem: &abi.Type{Size: 20, T: abi.AddressTy}}, Want: "address[]"},
{Type: &abi.Type{T: abi.ArrayTy, Size: 2, Elem: &abi.Type{Size: 20, T: abi.AddressTy}}, Want: "address[2]"},
{Type: &abi.Type{T: abi.TupleTy, TupleElems: []*abi.Type{&typeUint256, &typeUint256}}, Want: "(uint256,uint256)"},
{Type: &abi.Type{T: abi.TupleTy, TupleElems: []*abi.Type{{T: abi.TupleTy, TupleElems: []*abi.Type{&typeUint256, &typeUint256}}, &typeUint256}}, Want: "((uint256,uint256),uint256)"},
}
for i, test := range tests {
t.Run(strconv.Itoa(i), func(t *testing.T) {
got := typeToString(test.Type)
if test.Want != got {
t.Fatalf("want %q, got %q", test.Want, got)
}
})
}
}
var (
big1 = big.NewInt(1)
hex1 = common.FromHex("0x0000000000000000000000000000000000000000000000000000000000000001")
)
func TestTypeMapping(t *testing.T) {
tests := []struct {
RAWType string
Data []byte
Arg any
Want any
}{
{RAWType: "bool", Data: hex1, Arg: new(bool), Want: ptr(true)},
{RAWType: "int8", Data: hex1, Arg: new(int8), Want: ptr[int8](1)},
{RAWType: "int16", Data: hex1, Arg: new(int16), Want: ptr[int16](1)},
{RAWType: "int24", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "int32", Data: hex1, Arg: new(int32), Want: ptr[int32](1)},
{RAWType: "int40", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "int48", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "int56", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "int64", Data: hex1, Arg: new(int64), Want: ptr[int64](1)},
{RAWType: "int72", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "int80", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "int88", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "int96", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "int104", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "int112", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "int120", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "int128", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "int136", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "int144", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "int152", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "int160", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "int168", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "int176", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "int184", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "int192", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "int200", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "int208", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "int216", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "int224", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "int232", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "int240", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "int248", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "int256", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "int", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "uint8", Data: hex1, Arg: new(uint8), Want: ptr[uint8](1)},
{RAWType: "uint16", Data: hex1, Arg: new(uint16), Want: ptr[uint16](1)},
{RAWType: "uint24", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "uint32", Data: hex1, Arg: new(uint32), Want: ptr[uint32](1)},
{RAWType: "uint40", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "uint48", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "uint56", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "uint64", Data: hex1, Arg: new(uint64), Want: ptr[uint64](1)},
{RAWType: "uint72", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "uint80", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "uint88", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "uint96", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "uint104", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "uint112", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "uint120", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "uint128", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "uint136", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "uint144", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "uint152", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "uint160", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "uint168", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "uint176", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "uint184", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "uint192", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "uint200", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "uint208", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "uint216", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "uint224", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "uint232", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "uint240", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "uint248", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "uint256", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "uint", Data: hex1, Arg: new(big.Int), Want: big1},
{RAWType: "bytes1", Data: hex1, Arg: new([1]byte), Want: &[1]byte{}},
{RAWType: "bytes2", Data: hex1, Arg: new([2]byte), Want: &[2]byte{}},
{RAWType: "bytes3", Data: hex1, Arg: new([3]byte), Want: &[3]byte{}},
{RAWType: "bytes4", Data: hex1, Arg: new([4]byte), Want: &[4]byte{}},
{RAWType: "bytes5", Data: hex1, Arg: new([5]byte), Want: &[5]byte{}},
{RAWType: "bytes6", Data: hex1, Arg: new([6]byte), Want: &[6]byte{}},
{RAWType: "bytes7", Data: hex1, Arg: new([7]byte), Want: &[7]byte{}},
{RAWType: "bytes8", Data: hex1, Arg: new([8]byte), Want: &[8]byte{}},
{RAWType: "bytes9", Data: hex1, Arg: new([9]byte), Want: &[9]byte{}},
{RAWType: "bytes10", Data: hex1, Arg: new([10]byte), Want: &[10]byte{}},
{RAWType: "bytes11", Data: hex1, Arg: new([11]byte), Want: &[11]byte{}},
{RAWType: "bytes12", Data: hex1, Arg: new([12]byte), Want: &[12]byte{}},
{RAWType: "bytes13", Data: hex1, Arg: new([13]byte), Want: &[13]byte{}},
{RAWType: "bytes14", Data: hex1, Arg: new([14]byte), Want: &[14]byte{}},
{RAWType: "bytes15", Data: hex1, Arg: new([15]byte), Want: &[15]byte{}},
{RAWType: "bytes16", Data: hex1, Arg: new([16]byte), Want: &[16]byte{}},
{RAWType: "bytes17", Data: hex1, Arg: new([17]byte), Want: &[17]byte{}},
{RAWType: "bytes18", Data: hex1, Arg: new([18]byte), Want: &[18]byte{}},
{RAWType: "bytes19", Data: hex1, Arg: new([19]byte), Want: &[19]byte{}},
{RAWType: "bytes20", Data: hex1, Arg: new([20]byte), Want: &[20]byte{}},
{RAWType: "address", Data: hex1, Arg: new(common.Address), Want: &common.Address{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}},
{RAWType: "bytes21", Data: hex1, Arg: new([21]byte), Want: &[21]byte{}},
{RAWType: "bytes22", Data: hex1, Arg: new([22]byte), Want: &[22]byte{}},
{RAWType: "bytes23", Data: hex1, Arg: new([23]byte), Want: &[23]byte{}},
{RAWType: "bytes24", Data: hex1, Arg: new([24]byte), Want: &[24]byte{}},
{RAWType: "bytes25", Data: hex1, Arg: new([25]byte), Want: &[25]byte{}},
{RAWType: "bytes26", Data: hex1, Arg: new([26]byte), Want: &[26]byte{}},
{RAWType: "bytes27", Data: hex1, Arg: new([27]byte), Want: &[27]byte{}},
{RAWType: "bytes28", Data: hex1, Arg: new([28]byte), Want: &[28]byte{}},
{RAWType: "bytes29", Data: hex1, Arg: new([29]byte), Want: &[29]byte{}},
{RAWType: "bytes30", Data: hex1, Arg: new([30]byte), Want: &[30]byte{}},
{RAWType: "bytes31", Data: hex1, Arg: new([31]byte), Want: &[31]byte{}},
{RAWType: "bytes32", Data: hex1, Arg: new([32]byte), Want: &[32]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
gitextract_vxq391jt/
├── .gitattributes
├── .github/
│ ├── dependabot.yml
│ └── workflows/
│ ├── doc.yml
│ └── go.yml
├── .gitignore
├── LICENSE
├── README.md
├── client.go
├── client_test.go
├── docs/
│ ├── components/
│ │ └── DocLink.jsx
│ ├── next.config.js
│ ├── package.json
│ ├── pages/
│ │ ├── 404.mdx
│ │ ├── _app.js
│ │ ├── _meta.js
│ │ ├── examples/
│ │ │ ├── _meta.js
│ │ │ └── index.mdx
│ │ ├── examples.mdx
│ │ ├── helper-abi.mdx
│ │ ├── helper-utils.mdx
│ │ ├── index.mdx
│ │ ├── rpc-extension.mdx
│ │ ├── rpc-methods/
│ │ │ ├── _meta.js
│ │ │ ├── admin.mdx
│ │ │ ├── debug.mdx
│ │ │ ├── eth.mdx
│ │ │ ├── net.mdx
│ │ │ ├── txpool.mdx
│ │ │ └── web3.mdx
│ │ ├── rpc-methods.mdx
│ │ ├── rpc-overview.mdx
│ │ ├── style.css
│ │ ├── vm-overview.mdx
│ │ ├── vm-testing.mdx
│ │ └── vm-tracing.mdx
│ ├── postcss.config.cjs
│ ├── public/
│ │ ├── _redirects
│ │ └── robots.txt
│ ├── tailwind.config.js
│ └── theme.config.jsx
├── event.go
├── event_test.go
├── example_test.go
├── func.go
├── func_test.go
├── go.mod
├── go.sum
├── internal/
│ ├── abi/
│ │ ├── arguments.go
│ │ ├── arguments_test.go
│ │ ├── copy.go
│ │ ├── copy_test.go
│ │ ├── doc.go
│ │ ├── lexer.go
│ │ ├── lexer_test.go
│ │ ├── parser.go
│ │ ├── parser_test.go
│ │ ├── tuple.go
│ │ └── tuple_test.go
│ ├── cmp.go
│ ├── cmp_test.go
│ ├── crypto/
│ │ └── keccak.go
│ ├── fourbyte/
│ │ ├── events.go
│ │ ├── events.txt
│ │ ├── fourbyte.go
│ │ ├── funcs.go
│ │ ├── funcs.txt
│ │ └── gen.go
│ ├── hexutil/
│ │ ├── bytes.go
│ │ ├── bytes_test.go
│ │ ├── hash.go
│ │ └── hash_test.go
│ ├── mod/
│ │ ├── root.go
│ │ └── root_test.go
│ └── module/
│ ├── factory.go
│ ├── util.go
│ └── util_test.go
├── module/
│ ├── admin/
│ │ ├── admin.go
│ │ ├── admin_test.go
│ │ └── testdata/
│ │ ├── add_peer.golden
│ │ ├── add_trusted_peer.golden
│ │ ├── node_info.golden
│ │ ├── remove_peer.golden
│ │ └── remove_trusted_peer.golden
│ ├── debug/
│ │ ├── call_trace.go
│ │ ├── call_trace_test.go
│ │ ├── doc.go
│ │ ├── testdata/
│ │ │ ├── traceCall.golden
│ │ │ ├── traceCall_callTracer.golden
│ │ │ ├── traceTx__1150000_0.golden
│ │ │ ├── traceTx__12244000_0.golden
│ │ │ └── traceTx_revertReason.golden
│ │ ├── trace.go
│ │ └── trace_test.go
│ ├── eth/
│ │ ├── balance.go
│ │ ├── balance_test.go
│ │ ├── block.go
│ │ ├── block_number.go
│ │ ├── block_number_test.go
│ │ ├── block_test.go
│ │ ├── call.go
│ │ ├── call_test.go
│ │ ├── chain_id.go
│ │ ├── chain_id_test.go
│ │ ├── code.go
│ │ ├── code_test.go
│ │ ├── doc.go
│ │ ├── gas_price.go
│ │ ├── gas_price_test.go
│ │ ├── gas_tip_cap.go
│ │ ├── gas_tip_cap_test.go
│ │ ├── get_logs.go
│ │ ├── get_logs_test.go
│ │ ├── storage_at.go
│ │ ├── storage_at_test.go
│ │ ├── subscribe.go
│ │ ├── syncing.go
│ │ ├── syncing_test.go
│ │ ├── testdata/
│ │ │ ├── block_number.golden
│ │ │ ├── block_transaction_count_by_hash__0x00.golden
│ │ │ ├── block_transaction_count_by_hash__15050000.golden
│ │ │ ├── block_transaction_count_by_number__15050000.golden
│ │ │ ├── call_func.golden
│ │ │ ├── call_func__overrides.golden
│ │ │ ├── chain_id.golden
│ │ │ ├── create_access_list.golden
│ │ │ ├── estimate_gas.golden
│ │ │ ├── gas_price.golden
│ │ │ ├── gas_tip_cap.golden
│ │ │ ├── get_balance.golden
│ │ │ ├── get_balance__at_block.golden
│ │ │ ├── get_block_by_hash__0x00.golden
│ │ │ ├── get_block_by_hash__1.golden
│ │ │ ├── get_block_by_hash__12965000.golden
│ │ │ ├── get_block_by_hash__18000000.golden
│ │ │ ├── get_block_by_hash__46147.golden
│ │ │ ├── get_block_by_number__1.golden
│ │ │ ├── get_block_by_number__12965000.golden
│ │ │ ├── get_block_by_number__46147.golden
│ │ │ ├── get_block_by_number__999999999.golden
│ │ │ ├── get_block_receipts.golden
│ │ │ ├── get_code.golden
│ │ │ ├── get_logs.golden
│ │ │ ├── get_storage_at.golden
│ │ │ ├── get_storage_at__number.golden
│ │ │ ├── get_transaction_by_block_hash_and_index.golden
│ │ │ ├── get_transaction_by_block_hash_and_index__300.golden
│ │ │ ├── get_transaction_by_block_number_and_index.golden
│ │ │ ├── get_transaction_by_hash__0x00.golden
│ │ │ ├── get_transaction_by_hash__type0.golden
│ │ │ ├── get_transaction_by_hash__type2.golden
│ │ │ ├── get_transaction_count.golden
│ │ │ ├── get_transaction_receipt.golden
│ │ │ ├── get_transaction_receipt_0x00.golden
│ │ │ ├── send_raw_transaction.golden
│ │ │ ├── syncing__false.golden
│ │ │ ├── syncing__true.golden
│ │ │ ├── uncle_by_hash_and_index__15050036.golden
│ │ │ ├── uncle_by_hash_and_index__15050036_1.golden
│ │ │ ├── uncle_by_number_and_index__15050036.golden
│ │ │ ├── uncle_count_by_hash__15050036.golden
│ │ │ └── uncle_count_by_number__15050036.golden
│ │ ├── tx.go
│ │ ├── tx_test.go
│ │ ├── uncle.go
│ │ └── uncle_test.go
│ ├── net/
│ │ ├── net.go
│ │ ├── net_test.go
│ │ └── testdata/
│ │ ├── listening.golden
│ │ ├── peer_count.golden
│ │ └── version.golden
│ ├── txpool/
│ │ ├── content.go
│ │ ├── content_test.go
│ │ ├── doc.go
│ │ ├── status.go
│ │ ├── status_test.go
│ │ └── testdata/
│ │ ├── content.golden
│ │ ├── contentFrom.golden
│ │ └── status.golden
│ └── web3/
│ ├── testdata/
│ │ ├── client_version.golden
│ │ └── client_version__err.golden
│ ├── web3.go
│ └── web3_test.go
├── rpctest/
│ ├── server.go
│ └── test_case.go
├── testdata/
│ └── w3vm/
│ ├── 1_12243997.json
│ ├── 1_12243998.json
│ ├── 1_12243999.json
│ ├── 1_12244000.json
│ ├── 1_12964997.json
│ ├── 1_12964998.json
│ ├── 1_12964999.json
│ ├── 1_12965000.json
│ ├── 1_13772997.json
│ ├── 1_13772998.json
│ ├── 1_13772999.json
│ ├── 1_13773000.json
│ ├── 1_15049997.json
│ ├── 1_15049998.json
│ ├── 1_15049999.json
│ ├── 1_15050000.json
│ ├── 1_15537391.json
│ ├── 1_15537392.json
│ ├── 1_15537393.json
│ ├── 1_15537394.json
│ ├── 1_17034867.json
│ ├── 1_17034868.json
│ ├── 1_17034869.json
│ ├── 1_17034870.json
│ ├── 1_18999999.json
│ ├── 1_19000000.json
│ ├── 1_19000001.json
│ ├── 1_19000002.json
│ ├── 1_19000003.json
│ ├── 1_19000004.json
│ ├── 1_19000005.json
│ ├── 1_19000006.json
│ ├── 1_19000007.json
│ ├── 1_19000008.json
│ ├── 1_19426484.json
│ ├── 1_19426485.json
│ ├── 1_19426486.json
│ ├── 1_19426487.json
│ ├── 1_19999999.json
│ ├── 1_4369997.json
│ ├── 1_4369998.json
│ ├── 1_4369999.json
│ ├── 1_4370000.json
│ ├── 1_7279997.json
│ ├── 1_7279998.json
│ ├── 1_7279999.json
│ ├── 1_7280000.json
│ ├── 1_9068997.json
│ ├── 1_9068998.json
│ ├── 1_9068999.json
│ ├── 1_9069000.json
│ ├── 1_9199997.json
│ ├── 1_9199998.json
│ ├── 1_9199999.json
│ ├── 1_9200000.json
│ ├── 1_header_hashes.json
│ └── contracts.json
├── util.go
├── util_test.go
├── w3types/
│ ├── interfaces.go
│ ├── interfaces_test.go
│ ├── message.go
│ ├── rpc.go
│ ├── rpc_test.go
│ ├── state.go
│ └── state_test.go
└── w3vm/
├── bench_test.go
├── db.go
├── example_test.go
├── fetcher.go
├── fetcher_test.go
├── hooks/
│ └── call_tracer.go
├── receipt.go
├── testdata/
│ ├── burntpix.genesis.json
│ └── weth9.bytecode
├── util.go
├── util_test.go
├── vm.go
└── vm_test.go
SYMBOL INDEX (583 symbols across 95 files)
FILE: client.go
type Client (line 22) | type Client struct
method Close (line 70) | func (c *Client) Close() error {
method CallCtx (line 80) | func (c *Client) CallCtx(ctx context.Context, calls ...w3types.RPCCall...
method Call (line 140) | func (c *Client) Call(calls ...w3types.RPCCaller) error {
method SubscribeCtx (line 145) | func (c *Client) SubscribeCtx(ctx context.Context, s w3types.RPCSubscr...
method Subscribe (line 154) | func (c *Client) Subscribe(s w3types.RPCSubscriber) (*rpc.ClientSubscr...
method rateLimit (line 158) | func (c *Client) rateLimit(ctx context.Context, batchElems []rpc.Batch...
function NewClient (line 31) | func NewClient(client *rpc.Client, opts ...Option) *Client {
function Dial (line 50) | func Dial(rawurl string, opts ...Option) (*Client, error) {
function MustDial (line 59) | func MustDial(rawurl string, opts ...Option) *Client {
type CallErrors (line 181) | type CallErrors
method Error (line 183) | func (e CallErrors) Error() string {
method Is (line 203) | func (e CallErrors) Is(target error) bool {
type Option (line 209) | type Option
function WithRateLimiter (line 216) | func WithRateLimiter(rl *rate.Limiter, costFunc func(methods []string) (...
FILE: client_test.go
function TestClientCall (line 34) | func TestClientCall(t *testing.T) {
function TestClientCall_CallErrors (line 107) | func TestClientCall_CallErrors(t *testing.T) {
type testCaller (line 131) | type testCaller struct
method CreateRequest (line 136) | func (c *testCaller) CreateRequest() (elem rpc.BatchElem, err error) {
method HandleResponse (line 140) | func (c *testCaller) HandleResponse(elem rpc.BatchElem) (err error) {
function BenchmarkCall_BalanceNonce (line 144) | func BenchmarkCall_BalanceNonce(b *testing.B) {
function BenchmarkCall_Balance100 (line 178) | func BenchmarkCall_Balance100(b *testing.B) {
function BenchmarkCall_BalanceOf100 (line 214) | func BenchmarkCall_BalanceOf100(b *testing.B) {
function BenchmarkCall_Block100 (line 260) | func BenchmarkCall_Block100(b *testing.B) {
FILE: docs/pages/_app.js
function Nextra (line 7) | function Nextra({ Component, pageProps }) {
FILE: event.go
type Event (line 14) | type Event struct
method DecodeArgs (line 67) | func (e *Event) DecodeArgs(log *types.Log, args ...any) error {
function NewEvent (line 31) | func NewEvent(signature string, tuples ...any) (*Event, error) {
function MustNewEvent (line 58) | func MustNewEvent(signature string, tuples ...any) *Event {
FILE: event_test.go
function TestNewEvent (line 15) | func TestNewEvent(t *testing.T) {
function TestEventDecodeArgs (line 67) | func TestEventDecodeArgs(t *testing.T) {
FILE: example_test.go
function ExampleClient_batchCallFunc (line 39) | func ExampleClient_batchCallFunc() {
function ExampleClient_batchCallFuncUniswapQuoter (line 63) | func ExampleClient_batchCallFuncUniswapQuoter() {
function ExampleClient_batchEOAState (line 109) | func ExampleClient_batchEOAState() {
function ExampleClient_batchTxDetails (line 125) | func ExampleClient_batchTxDetails() {
function ExampleClient_batchBlocks (line 143) | func ExampleClient_batchBlocks() {
function ExampleClient_batchHandleError (line 165) | func ExampleClient_batchHandleError() {
function ExampleClient_callFunc (line 194) | func ExampleClient_callFunc() {
function ExampleClient_callFuncWithStateOverride (line 208) | func ExampleClient_callFuncWithStateOverride() {
function ExampleClient_sendETHTransfer (line 226) | func ExampleClient_sendETHTransfer() {
function ExampleClient_sendTokenTransfer (line 256) | func ExampleClient_sendTokenTransfer() {
function ExampleClient_subscribeToPendingTransactions (line 292) | func ExampleClient_subscribeToPendingTransactions() {
function ExampleClient_rateLimitByRequest (line 318) | func ExampleClient_rateLimitByRequest() {
function ExampleClient_rateLimitByComputeUnits (line 331) | func ExampleClient_rateLimitByComputeUnits() {
function ExampleFunc_erc20 (line 366) | func ExampleFunc_erc20() {
function ExampleFunc_balanceOf (line 384) | func ExampleFunc_balanceOf() {
function ExampleFunc_uniswapV4Swap (line 404) | func ExampleFunc_uniswapV4Swap() {
function ExampleFunc_DecodeReturns_getReserves (line 445) | func ExampleFunc_DecodeReturns_getReserves() {
function ExampleEvent_decodeTransferEvent (line 469) | func ExampleEvent_decodeTransferEvent() {
FILE: func.go
type Func (line 30) | type Func struct
method EncodeArgs (line 93) | func (f *Func) EncodeArgs(args ...any) ([]byte, error) {
method DecodeArgs (line 98) | func (f *Func) DecodeArgs(input []byte, args ...any) error {
method DecodeReturns (line 109) | func (f *Func) DecodeReturns(output []byte, returns ...any) error {
function NewFunc (line 57) | func NewFunc(signature, returns string, tuples ...any) (*Func, error) {
function MustNewFunc (line 83) | func MustNewFunc(signature, returns string, tuples ...any) *Func {
function selector (line 131) | func selector(signature string) (selector [4]byte) {
FILE: func_test.go
function TestNewFunc (line 18) | func TestNewFunc(t *testing.T) {
function TestFuncEncodeArgs (line 86) | func TestFuncEncodeArgs(t *testing.T) {
function TestFuncDecodeArgs (line 236) | func TestFuncDecodeArgs(t *testing.T) {
function TestFuncDecodeReturns (line 452) | func TestFuncDecodeReturns(t *testing.T) {
function ptr (line 527) | func ptr[T any](v T) *T { return &v }
type tuple (line 529) | type tuple struct
type tupleWithTag (line 534) | type tupleWithTag struct
type tupleWithNesting (line 539) | type tupleWithNesting struct
type tupleWithBytes (line 544) | type tupleWithBytes struct
type tupleWithUnexportedProperty (line 549) | type tupleWithUnexportedProperty struct
type tupleWithWrongOrder (line 555) | type tupleWithWrongOrder struct
type tupleWithMoreArgs (line 560) | type tupleWithMoreArgs struct
type tupleIssue35 (line 566) | type tupleIssue35 struct
type tupleNested (line 572) | type tupleNested struct
function BenchmarkFuncEncode (line 577) | func BenchmarkFuncEncode(b *testing.B) {
FILE: internal/abi/arguments.go
type Arguments (line 13) | type Arguments
method Signature (line 15) | func (a Arguments) Signature() string {
method SignatureWithName (line 27) | func (a Arguments) SignatureWithName(name string) string {
method Encode (line 32) | func (a Arguments) Encode(args ...any) ([]byte, error) {
method EncodeWithSelector (line 42) | func (a Arguments) EncodeWithSelector(selector [4]byte, args ...any) (...
method EncodeWithSignature (line 54) | func (a Arguments) EncodeWithSignature(signature string, args ...any) ...
method Decode (line 62) | func (a Arguments) Decode(data []byte, args ...any) error {
function typeToString (line 82) | func typeToString(t *abi.Type) string {
FILE: internal/abi/arguments_test.go
function TestSignature (line 15) | func TestSignature(t *testing.T) {
function TestSignatureWithName (line 58) | func TestSignatureWithName(t *testing.T) {
function TestEncode (line 86) | func TestEncode(t *testing.T) {
function TestEncodeWithSelector (line 112) | func TestEncodeWithSelector(t *testing.T) {
function TestEncodeWithSignature (line 141) | func TestEncodeWithSignature(t *testing.T) {
function TestDecode (line 169) | func TestDecode(t *testing.T) {
function TestTypeToString (line 313) | func TestTypeToString(t *testing.T) {
function TestTypeMapping (line 390) | func TestTypeMapping(t *testing.T) {
FILE: internal/abi/copy.go
function Copy (line 73) | func Copy(dst, src any) error {
function rCopy (line 100) | func rCopy(dst, src reflect.Value) error {
function set (line 114) | func set(dst, src reflect.Value) error {
function setStruct (line 138) | func setStruct(dst, src reflect.Value) error {
function setSlice (line 177) | func setSlice(dst, src reflect.Value) error {
function setArray (line 197) | func setArray(dst, src reflect.Value) error {
function dereference (line 212) | func dereference(v reflect.Value) reflect.Value {
function reference (line 219) | func reference(v reflect.Value) reflect.Value {
FILE: internal/abi/copy_test.go
function TestCopy (line 14) | func TestCopy(t *testing.T) {
function ptr (line 313) | func ptr[T any](v T) *T { return &v }
function val (line 314) | func val[T any](v *T) T { return *v }
type tuple0 (line 316) | type tuple0 struct
type tuple1 (line 321) | type tuple1 struct
type tuple2 (line 326) | type tuple2 struct
type tuple3 (line 331) | type tuple3 struct
FILE: internal/abi/lexer.go
type item (line 12) | type item struct
method String (line 19) | func (i item) String() string {
method IsType (line 27) | func (i *item) IsType() (*abi.Type, bool) {
type itemType (line 17) | type itemType
constant itemTypeID (line 37) | itemTypeID itemType = iota
constant itemTypePunct (line 38) | itemTypePunct
constant itemTypeNum (line 39) | itemTypeNum
constant itemTypeEOF (line 40) | itemTypeEOF
constant eof (line 42) | eof rune = -1
constant num0 (line 44) | num0 = "123456789"
constant num (line 45) | num = "0" + num0
constant id0 (line 46) | id0 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"
constant id (line 47) | id = id0 + num
constant space (line 48) | space = " \t\r\n"
type lexer (line 52) | type lexer struct
method nextItem (line 63) | func (l *lexer) nextItem() (*item, error) {
method next (line 88) | func (l *lexer) next() (next rune) {
method backup (line 98) | func (l *lexer) backup() {
method ignore (line 102) | func (l *lexer) ignore() {
method peek (line 106) | func (l *lexer) peek() (next rune) {
method accept (line 112) | func (l *lexer) accept(valid string) bool {
method acceptRun (line 121) | func (l *lexer) acceptRun(valid string) {
method token (line 127) | func (l *lexer) token() string {
function newLexer (line 59) | func newLexer(input string) *lexer {
FILE: internal/abi/lexer_test.go
function TestLexer (line 13) | func TestLexer(t *testing.T) {
function lex (line 42) | func lex(input string) ([]*item, error) {
FILE: internal/abi/parser.go
function Parse (line 15) | func Parse(s string, tuples ...any) (a Arguments, err error) {
function ParseWithName (line 27) | func ParseWithName(s string, tuples ...any) (name string, a Arguments, e...
type parser (line 37) | type parser struct
method next (line 60) | func (p *parser) next() *item {
method backup (line 77) | func (p *parser) backup() {
method peek (line 81) | func (p *parser) peek() *item {
method parseArgsWithName (line 87) | func (p *parser) parseArgsWithName() error {
method parseArgs (line 124) | func (p *parser) parseArgs() error {
method parseType (line 191) | func (p *parser) parseType() (*abi.Type, error) {
method parseTupleType (line 232) | func (p *parser) parseTupleType(i int) (*abi.Type, string, error) {
method parseTupleTypes (line 252) | func (p *parser) parseTupleTypes() (*abi.Type, error) {
method parseSliceOrArray (line 292) | func (p *parser) parseSliceOrArray(typ *abi.Type) (*abi.Type, error) {
function newParser (line 51) | func newParser(lexer *lexer, tuples []any) *parser {
FILE: internal/abi/parser_test.go
function TestParseArgs (line 24) | func TestParseArgs(t *testing.T) {
function TestParseArgsWithName (line 533) | func TestParseArgsWithName(t *testing.T) {
function BenchmarkParseArgsWithName (line 660) | func BenchmarkParseArgsWithName(b *testing.B) {
type simpleStruct (line 704) | type simpleStruct struct
type simpleStructWithoutTags (line 709) | type simpleStructWithoutTags struct
type nestedStruct (line 714) | type nestedStruct struct
type complexStruct (line 719) | type complexStruct struct
type arrayStruct (line 726) | type arrayStruct struct
type emptyStruct (line 731) | type emptyStruct struct
type structWithInvalidField (line 734) | type structWithInvalidField struct
FILE: internal/abi/tuple.go
function tupleMap (line 16) | func tupleMap(tuples ...any) (map[string]reflect.Type, error) {
function buildTuples (line 32) | func buildTuples(tuples ...any) (map[string]abi.Argument, error) {
function typeOfField (line 59) | func typeOfField(field reflect.StructField) (*abi.Type, error) {
function typeOf (line 66) | func typeOf(typ reflect.Type, abiType string) (*abi.Type, error) {
function toCamelCase (line 184) | func toCamelCase(s string) string {
FILE: internal/abi/tuple_test.go
function TestTupleMap (line 19) | func TestTupleMap(t *testing.T) {
type Tuple1 (line 70) | type Tuple1 struct
type Tuple2 (line 74) | type Tuple2 struct
function TestTypeOfField (line 79) | func TestTypeOfField(t *testing.T) {
function TestToCamelCase (line 225) | func TestToCamelCase(t *testing.T) {
FILE: internal/cmp.go
function EquateErrors (line 8) | func EquateErrors() cmp.Option {
function areConcreteErrors (line 12) | func areConcreteErrors(x, y any) bool {
function compareErrors (line 18) | func compareErrors(x, y any) bool {
FILE: internal/cmp_test.go
function TestEquateErrors (line 12) | func TestEquateErrors(t *testing.T) {
FILE: internal/crypto/keccak.go
function Keccak256Hash (line 20) | func Keccak256Hash(data ...[]byte) (hash common.Hash) {
function Keccak256 (line 40) | func Keccak256(data ...[]byte) (hash []byte) {
FILE: internal/fourbyte/fourbyte.go
function Function (line 22) | func Function(sig [4]byte, addr common.Address) (fn *w3.Func, isPrecompi...
function Event (line 36) | func Event(topic0 [32]byte, addr common.Address) *w3.Event {
FILE: internal/fourbyte/gen.go
function main (line 18) | func main() {
function genFuncs (line 46) | func genFuncs(fn, goFn string) error {
function genEvents (line 123) | func genEvents(fn, goFn string) error {
type model (line 191) | type model struct
type function (line 196) | type function struct
type event (line 202) | type event struct
FILE: internal/hexutil/bytes.go
type Bytes (line 8) | type Bytes
method UnmarshalText (line 11) | func (b *Bytes) UnmarshalText(data []byte) error {
method MarshalText (line 22) | func (b Bytes) MarshalText() ([]byte, error) {
FILE: internal/hexutil/bytes_test.go
function TestBytesUnmarshalText (line 21) | func TestBytesUnmarshalText(t *testing.T) {
function TestBytesMarshalText (line 35) | func TestBytesMarshalText(t *testing.T) {
FILE: internal/hexutil/hash.go
type Hash (line 13) | type Hash
method UnmarshalText (line 15) | func (h *Hash) UnmarshalText(text []byte) error {
method MarshalText (line 28) | func (h Hash) MarshalText() ([]byte, error) {
FILE: internal/hexutil/hash_test.go
function TestHashUnmarshalText (line 23) | func TestHashUnmarshalText(t *testing.T) {
function TestHashMarshalText (line 38) | func TestHashMarshalText(t *testing.T) {
FILE: internal/mod/root.go
function init (line 12) | func init() {
FILE: internal/mod/root_test.go
function TestModRoot (line 10) | func TestModRoot(t *testing.T) {
FILE: internal/module/factory.go
type Option (line 16) | type Option
type ArgsWrapperFunc (line 18) | type ArgsWrapperFunc
type RetWrapperFunc (line 20) | type RetWrapperFunc
type Factory (line 22) | type Factory struct
function NewFactory (line 31) | func NewFactory[T any](method string, args []any, opts ...Option[T]) *Fa...
method Returns (line 45) | func (f Factory[T]) Returns(ret *T) w3types.RPCCaller {
method CreateRequest (line 50) | func (f Factory[T]) CreateRequest() (rpc.BatchElem, error) {
method HandleResponse (line 66) | func (f Factory[T]) HandleResponse(elem rpc.BatchElem) error {
function WithArgsWrapper (line 82) | func WithArgsWrapper[T any](fn ArgsWrapperFunc) Option[T] {
function WithRetWrapper (line 88) | func WithRetWrapper[T any](fn RetWrapperFunc[T]) Option[T] {
function HexBigRetWrapper (line 94) | func HexBigRetWrapper(ret **big.Int) any {
function HexUintRetWrapper (line 98) | func HexUintRetWrapper(ret *uint) any { return (*hexutil.Uint)(ret) }
function HexUint64RetWrapper (line 99) | func HexUint64RetWrapper(ret *uint64) any { return (*hexutil.Uint64)(ret) }
function HexBytesRetWrapper (line 100) | func HexBytesRetWrapper(ret *[]byte) any { return (*hexutil.Bytes)(ret) }
FILE: internal/module/util.go
function BlockNumberArg (line 12) | func BlockNumberArg(blockNumber *big.Int) string {
FILE: internal/module/util_test.go
function TestBlockNumberArg (line 9) | func TestBlockNumberArg(t *testing.T) {
FILE: module/admin/admin.go
function AddPeer (line 18) | func AddPeer(url *enode.Node) w3types.RPCCallerFactory[bool] {
function RemovePeer (line 27) | func RemovePeer(url *enode.Node) w3types.RPCCallerFactory[bool] {
function AddTrustedPeer (line 36) | func AddTrustedPeer(url *enode.Node) w3types.RPCCallerFactory[bool] {
function RemoveTrustedPeer (line 45) | func RemoveTrustedPeer(url *enode.Node) w3types.RPCCallerFactory[bool] {
function NodeInfo (line 53) | func NodeInfo() w3types.RPCCallerFactory[*NodeInfoResponse] {
type NodeInfoResponse (line 60) | type NodeInfoResponse struct
type PortsInfo (line 70) | type PortsInfo struct
type ProtocolInfo (line 75) | type ProtocolInfo struct
FILE: module/admin/admin_test.go
function TestAddPeer (line 16) | func TestAddPeer(t *testing.T) {
function TestRemovePeer (line 26) | func TestRemovePeer(t *testing.T) {
function TestAddTrustedPeer (line 36) | func TestAddTrustedPeer(t *testing.T) {
function TestRemoveTrustedPeer (line 46) | func TestRemoveTrustedPeer(t *testing.T) {
function TestNodeInfo (line 56) | func TestNodeInfo(t *testing.T) {
FILE: module/debug/call_trace.go
function CallTraceCall (line 14) | func CallTraceCall(msg *w3types.Message, blockNumber *big.Int, overrides...
function CallTraceTx (line 23) | func CallTraceTx(txHash common.Hash, overrides w3types.State) w3types.RP...
type CallTrace (line 30) | type CallTrace struct
method UnmarshalJSON (line 45) | func (c *CallTrace) UnmarshalJSON(data []byte) error {
type traceConfig (line 81) | type traceConfig struct
FILE: module/debug/call_trace_test.go
function TestCallTraceTx (line 12) | func TestCallTraceTx(t *testing.T) {
FILE: module/debug/trace.go
function TraceCall (line 18) | func TraceCall(msg *w3types.Message, blockNumber *big.Int, config *Trace...
function TraceTx (line 30) | func TraceTx(txHash common.Hash, config *TraceConfig) w3types.RPCCallerF...
type TraceConfig (line 40) | type TraceConfig struct
method MarshalJSON (line 50) | func (c *TraceConfig) MarshalJSON() ([]byte, error) {
type Trace (line 72) | type Trace struct
method UnmarshalJSON (line 79) | func (t *Trace) UnmarshalJSON(data []byte) error {
type StructLog (line 99) | type StructLog struct
method UnmarshalJSON (line 110) | func (l *StructLog) UnmarshalJSON(data []byte) error {
type optionalPrefixedHash (line 146) | type optionalPrefixedHash
method UnmarshalText (line 148) | func (h *optionalPrefixedHash) UnmarshalText(data []byte) error {
type memory (line 161) | type memory
method UnmarshalJSON (line 163) | func (m *memory) UnmarshalJSON(data []byte) error {
function msgArgsWrapper (line 176) | func msgArgsWrapper(slice []any) ([]any, error) {
FILE: module/debug/trace_test.go
function TestTraceTx (line 14) | func TestTraceTx(t *testing.T) {
function TestTraceCall (line 44) | func TestTraceCall(t *testing.T) {
FILE: module/eth/balance.go
function Balance (line 14) | func Balance(addr common.Address, blockNumber *big.Int) w3types.RPCCalle...
FILE: module/eth/balance_test.go
function TestBalance (line 12) | func TestBalance(t *testing.T) {
FILE: module/eth/block.go
function BlockByHash (line 14) | func BlockByHash(hash common.Hash) w3types.RPCCallerFactory[*types.Block] {
function BlockByNumber (line 24) | func BlockByNumber(number *big.Int) w3types.RPCCallerFactory[*types.Bloc...
function BlockTxCountByHash (line 34) | func BlockTxCountByHash(hash common.Hash) w3types.RPCCallerFactory[uint] {
function BlockTxCountByNumber (line 44) | func BlockTxCountByNumber(number *big.Int) w3types.RPCCallerFactory[uint] {
function HeaderByHash (line 53) | func HeaderByHash(hash common.Hash) w3types.RPCCallerFactory[*types.Head...
function HeaderByNumber (line 62) | func HeaderByNumber(number *big.Int) w3types.RPCCallerFactory[*types.Hea...
function blockRetWrapper (line 69) | func blockRetWrapper(ret **types.Block) any { *ret = new(types.Block); r...
type rpcBlock (line 71) | type rpcBlock struct
method UnmarshalJSON (line 73) | func (b *rpcBlock) UnmarshalJSON(data []byte) error {
FILE: module/eth/block_number.go
function BlockNumber (line 11) | func BlockNumber() w3types.RPCCallerFactory[*big.Int] {
FILE: module/eth/block_number_test.go
function TestBlockNumber (line 12) | func TestBlockNumber(t *testing.T) {
FILE: module/eth/block_test.go
function TestBlockByHash (line 15) | func TestBlockByHash(t *testing.T) {
function TestBlockByNumber (line 107) | func TestBlockByNumber(t *testing.T) {
function TestBlockTxCountByHash (line 172) | func TestBlockTxCountByHash(t *testing.T) {
function TestBlockTxCountByNumber (line 187) | func TestBlockTxCountByNumber(t *testing.T) {
function TestHeaderByHash (line 197) | func TestHeaderByHash(t *testing.T) {
function TestHeaderByNumber (line 224) | func TestHeaderByNumber(t *testing.T) {
function ptr (line 251) | func ptr[T any](v T) *T { return &v }
FILE: module/eth/call.go
function Call (line 18) | func Call(msg *w3types.Message, blockNumber *big.Int, overrides w3types....
function EstimateGas (line 35) | func EstimateGas(msg *w3types.Message, blockNumber *big.Int) w3types.RPC...
function AccessList (line 47) | func AccessList(msg *w3types.Message, blockNumber *big.Int) w3types.RPCC...
type AccessListResponse (line 55) | type AccessListResponse struct
method UnmarshalJSON (line 61) | func (resp *AccessListResponse) UnmarshalJSON(data []byte) error {
function msgArgsWrapper (line 77) | func msgArgsWrapper(slice []any) ([]any, error) {
function CallFunc (line 94) | func CallFunc(contract common.Address, f w3types.Func, args ...any) *Cal...
type CallFuncFactory (line 102) | type CallFuncFactory struct
method Returns (line 113) | func (f *CallFuncFactory) Returns(returns ...any) w3types.RPCCaller {
method From (line 118) | func (f *CallFuncFactory) From(from common.Address) *CallFuncFactory {
method Value (line 123) | func (f *CallFuncFactory) Value(value *big.Int) *CallFuncFactory {
method AtBlock (line 128) | func (f *CallFuncFactory) AtBlock(blockNumber *big.Int) *CallFuncFacto...
method Overrides (line 133) | func (f *CallFuncFactory) Overrides(overrides w3types.State) *CallFunc...
method CreateRequest (line 138) | func (f *CallFuncFactory) CreateRequest() (rpc.BatchElem, error) {
method HandleResponse (line 160) | func (f *CallFuncFactory) HandleResponse(elem rpc.BatchElem) error {
FILE: module/eth/call_test.go
function TestCall (line 17) | func TestCall(t *testing.T) {
function TestCallFunc (line 46) | func TestCallFunc(t *testing.T) {
function TestEstimateGas (line 67) | func TestEstimateGas(t *testing.T) {
function TestAccessList (line 81) | func TestAccessList(t *testing.T) {
FILE: module/eth/chain_id.go
function ChainID (line 9) | func ChainID() w3types.RPCCallerFactory[uint64] {
FILE: module/eth/chain_id_test.go
function TestChainID (line 10) | func TestChainID(t *testing.T) {
FILE: module/eth/code.go
function Code (line 14) | func Code(addr common.Address, blockNumber *big.Int) w3types.RPCCallerFa...
FILE: module/eth/code_test.go
function TestCode (line 11) | func TestCode(t *testing.T) {
FILE: module/eth/gas_price.go
function GasPrice (line 11) | func GasPrice() w3types.RPCCallerFactory[*big.Int] {
FILE: module/eth/gas_price_test.go
function TestGasPrice (line 12) | func TestGasPrice(t *testing.T) {
FILE: module/eth/gas_tip_cap.go
function GasTipCap (line 12) | func GasTipCap() w3types.RPCCallerFactory[*big.Int] {
FILE: module/eth/gas_tip_cap_test.go
function TestGasTipCap (line 12) | func TestGasTipCap(t *testing.T) {
FILE: module/eth/get_logs.go
function Logs (line 14) | func Logs(q ethereum.FilterQuery) w3types.RPCCallerFactory[[]types.Log] {
type logsFactory (line 18) | type logsFactory struct
method Returns (line 26) | func (f *logsFactory) Returns(logs *[]types.Log) w3types.RPCCaller {
method CreateRequest (line 32) | func (f *logsFactory) CreateRequest() (rpc.BatchElem, error) {
method HandleResponse (line 46) | func (f *logsFactory) HandleResponse(elem rpc.BatchElem) error {
function toFilterArg (line 53) | func toFilterArg(q ethereum.FilterQuery) (any, error) {
FILE: module/eth/get_logs_test.go
function TestLogs (line 15) | func TestLogs(t *testing.T) {
FILE: module/eth/storage_at.go
function StorageAt (line 15) | func StorageAt(addr common.Address, slot common.Hash, blockNumber *big.I...
FILE: module/eth/storage_at_test.go
function TestStorageAt (line 12) | func TestStorageAt(t *testing.T) {
FILE: module/eth/subscribe.go
function NewHeads (line 10) | func NewHeads(ch chan<- *types.Header) w3types.RPCSubscriber {
function PendingTransactions (line 15) | func PendingTransactions(ch chan<- *types.Transaction) w3types.RPCSubscr...
function NewLogs (line 20) | func NewLogs(ch chan<- *types.Log, q ethereum.FilterQuery) w3types.RPCSu...
type ethSubscription (line 25) | type ethSubscription struct
method CreateRequest (line 31) | func (s *ethSubscription[T]) CreateRequest() (string, any, []any, error) {
FILE: module/eth/syncing.go
function Syncing (line 9) | func Syncing() w3types.RPCCallerFactory[bool] {
function syncingRetWrapper (line 17) | func syncingRetWrapper(ret *bool) any {
type syncingBool (line 21) | type syncingBool
method UnmarshalJSON (line 23) | func (s *syncingBool) UnmarshalJSON(b []byte) error {
FILE: module/eth/syncing_test.go
function TestSyncing (line 10) | func TestSyncing(t *testing.T) {
FILE: module/eth/tx.go
function Tx (line 14) | func Tx(hash common.Hash) w3types.RPCCallerFactory[*types.Transaction] {
function TxByBlockHashAndIndex (line 22) | func TxByBlockHashAndIndex(blockHash common.Hash, index uint64) w3types....
function TxByBlockNumberAndIndex (line 30) | func TxByBlockNumberAndIndex(blockNumber *big.Int, index uint64) w3types...
function SendRawTx (line 38) | func SendRawTx(rawTx []byte) w3types.RPCCallerFactory[common.Hash] {
function SendTx (line 46) | func SendTx(tx *types.Transaction) w3types.RPCCallerFactory[common.Hash] {
function TxReceipt (line 63) | func TxReceipt(txHash common.Hash) w3types.RPCCallerFactory[*types.Recei...
function BlockReceipts (line 71) | func BlockReceipts(number *big.Int) w3types.RPCCallerFactory[types.Recei...
function Nonce (line 81) | func Nonce(addr common.Address, blockNumber *big.Int) w3types.RPCCallerF...
FILE: module/eth/tx_test.go
function TestTx (line 31) | func TestTx(t *testing.T) {
function TestTxByBlockNumberAndIndex (line 63) | func TestTxByBlockNumberAndIndex(t *testing.T) {
function TestSendTx (line 77) | func TestSendTx(t *testing.T) {
function TestTxReceipt (line 87) | func TestTxReceipt(t *testing.T) {
function TestBlockReceipts (line 129) | func TestBlockReceipts(t *testing.T) {
function TestNonce (line 168) | func TestNonce(t *testing.T) {
FILE: module/eth/uncle.go
function UncleByBlockHashAndIndex (line 15) | func UncleByBlockHashAndIndex(hash common.Hash, index uint) w3types.RPCC...
function UncleByBlockNumberAndIndex (line 24) | func UncleByBlockNumberAndIndex(number *big.Int, index uint) w3types.RPC...
function UncleCountByBlockHash (line 33) | func UncleCountByBlockHash(hash common.Hash) w3types.RPCCallerFactory[ui...
function UncleCountByBlockNumber (line 43) | func UncleCountByBlockNumber(number *big.Int) w3types.RPCCallerFactory[u...
FILE: module/eth/uncle_test.go
function blockNonce (line 33) | func blockNonce(data []byte) (nonce types.BlockNonce) {
function blockBloom (line 38) | func blockBloom(data []byte) (bloom types.Bloom) {
function TestUncleByBlockHashAndIndex (line 43) | func TestUncleByBlockHashAndIndex(t *testing.T) {
function TestUncleByBlockNumberAndIndex (line 58) | func TestUncleByBlockNumberAndIndex(t *testing.T) {
function TestUncleCountByBlockHash (line 68) | func TestUncleCountByBlockHash(t *testing.T) {
function TestUncleCountByBlockNumber (line 78) | func TestUncleCountByBlockNumber(t *testing.T) {
FILE: module/net/net.go
function Listening (line 12) | func Listening() w3types.RPCCallerFactory[bool] {
function PeerCount (line 20) | func PeerCount() w3types.RPCCallerFactory[int] {
function Version (line 28) | func Version() w3types.RPCCallerFactory[int] {
FILE: module/net/net_test.go
function TestListening (line 10) | func TestListening(t *testing.T) {
function TestPeerCount (line 20) | func TestPeerCount(t *testing.T) {
function TestVersion (line 30) | func TestVersion(t *testing.T) {
FILE: module/txpool/content.go
function Content (line 14) | func Content() w3types.RPCCallerFactory[*ContentResponse] {
function ContentFrom (line 23) | func ContentFrom(addr common.Address) w3types.RPCCallerFactory[*ContentF...
type ContentResponse (line 30) | type ContentResponse struct
method UnmarshalJSON (line 35) | func (c *ContentResponse) UnmarshalJSON(data []byte) error {
type ContentFromResponse (line 69) | type ContentFromResponse struct
method UnmarshalJSON (line 74) | func (cf *ContentFromResponse) UnmarshalJSON(data []byte) error {
FILE: module/txpool/content_test.go
function TestContent (line 14) | func TestContent(t *testing.T) {
function TestContentFrom (line 57) | func TestContentFrom(t *testing.T) {
FILE: module/txpool/status.go
function Status (line 12) | func Status() w3types.RPCCallerFactory[*StatusResponse] {
type StatusResponse (line 19) | type StatusResponse struct
method UnmarshalJSON (line 24) | func (s *StatusResponse) UnmarshalJSON(data []byte) error {
FILE: module/txpool/status_test.go
function TestStatus (line 10) | func TestStatus(t *testing.T) {
FILE: module/web3/web3.go
function ClientVersion (line 12) | func ClientVersion() w3types.RPCCallerFactory[string] {
FILE: module/web3/web3_test.go
function TestClientVersion (line 11) | func TestClientVersion(t *testing.T) {
FILE: rpctest/server.go
type Server (line 26) | type Server struct
method ServeHTTP (line 58) | func (srv *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
method URL (line 78) | func (srv *Server) URL() string {
method Close (line 83) | func (srv *Server) Close() {
method readGolden (line 87) | func (srv *Server) readGolden() {
function NewServer (line 39) | func NewServer(t *testing.T, r io.Reader) *Server {
function NewFileServer (line 49) | func NewFileServer(t *testing.T, filename string) *Server {
FILE: rpctest/test_case.go
type TestCase (line 16) | type TestCase struct
function RunTestCases (line 23) | func RunTestCases[T any](t *testing.T, tests []TestCase[T], opts ...cmp....
function comp (line 43) | func comp[T any](t *testing.T, wantVal, gotVal T, wantErr, gotErr error,...
FILE: util.go
function A (line 67) | func A(hexAddr string) (addr common.Address) {
function APtr (line 83) | func APtr(hexAddress string) *common.Address {
function B (line 93) | func B(hexBytes ...string) (bytes []byte) {
function H (line 112) | func H(hexHash string) (hash common.Hash) {
function I (line 139) | func I(strInt string) *big.Int {
function parseHexBig (line 146) | func parseHexBig(hexBig string) *big.Int {
function parseDecimal (line 154) | func parseDecimal(strBig string) *big.Int {
function FromWei (line 210) | func FromWei(wei *big.Int, decimals uint8) string {
function has0xPrefix (line 232) | func has0xPrefix(hexStr string) bool {
function BigMin (line 237) | func BigMin(a, b *big.Int) *big.Int {
function BigMax (line 245) | func BigMax(a, b *big.Int) *big.Int {
FILE: util_test.go
function ExampleI (line 14) | func ExampleI() {
function ExampleFromWei (line 26) | func ExampleFromWei() {
function TestA (line 33) | func TestA(t *testing.T) {
function TestB (line 71) | func TestB(t *testing.T) {
function TestH (line 103) | func TestH(t *testing.T) {
function TestI (line 141) | func TestI(t *testing.T) {
function strBig (line 211) | func strBig(s string) *big.Int {
function FuzzI (line 216) | func FuzzI(f *testing.F) {
function BenchmarkI (line 232) | func BenchmarkI(b *testing.B) {
function TestFromWei (line 251) | func TestFromWei(t *testing.T) {
function TestBigMin (line 294) | func TestBigMin(t *testing.T) {
function TestBigMax (line 313) | func TestBigMax(t *testing.T) {
FILE: w3types/interfaces.go
type Func (line 9) | type Func interface
type RPCCaller (line 23) | type RPCCaller interface
type RPCCallerFactory (line 32) | type RPCCallerFactory interface
type RPCSubscriber (line 39) | type RPCSubscriber interface
FILE: w3types/interfaces_test.go
function TxBySenderAndNonceFactory (line 13) | func TxBySenderAndNonceFactory(sender common.Address, nonce uint64) w3ty...
type getTransactionBySenderAndNonceFactory (line 23) | type getTransactionBySenderAndNonceFactory struct
method Returns (line 35) | func (f *getTransactionBySenderAndNonceFactory) Returns(txHash *common...
method CreateRequest (line 43) | func (f *getTransactionBySenderAndNonceFactory) CreateRequest() (rpc.B...
method HandleResponse (line 54) | func (f *getTransactionBySenderAndNonceFactory) HandleResponse(elem rp...
function ExampleRPCCaller_getTransactionBySenderAndNonce (line 61) | func ExampleRPCCaller_getTransactionBySenderAndNonce() {
FILE: w3types/message.go
type Message (line 18) | type Message struct
method Set (line 38) | func (msg *Message) Set(msg2 *Message) *Message {
method SetTx (line 58) | func (msg *Message) SetTx(tx *types.Transaction, signer types.Signer) ...
method MustSetTx (line 81) | func (msg *Message) MustSetTx(tx *types.Transaction, signer types.Sign...
method SetCallMsg (line 90) | func (msg *Message) SetCallMsg(callMsg ethereum.CallMsg) *Message {
method MarshalJSON (line 123) | func (msg *Message) MarshalJSON() ([]byte, error) {
method UnmarshalJSON (line 164) | func (msg *Message) UnmarshalJSON(data []byte) error {
type message (line 105) | type message struct
FILE: w3types/rpc.go
type BlockOverrides (line 11) | type BlockOverrides struct
method MarshalJSON (line 33) | func (o BlockOverrides) MarshalJSON() ([]byte, error) {
type blockOverrides (line 22) | type blockOverrides struct
FILE: w3types/rpc_test.go
function TestBlockOverrides_MarshalJSON (line 13) | func TestBlockOverrides_MarshalJSON(t *testing.T) {
FILE: w3types/state.go
type State (line 16) | type State
method SetGenesisAlloc (line 20) | func (s State) SetGenesisAlloc(alloc types.GenesisAlloc) State {
method Merge (line 35) | func (s State) Merge(other State) (merged State) {
type Account (line 54) | type Account struct
method deepCopy (line 64) | func (acc *Account) deepCopy() *Account {
method merge (line 79) | func (dst *Account) merge(src *Account) {
method CodeHash (line 105) | func (acc *Account) CodeHash() common.Hash {
method MarshalJSON (line 121) | func (acc *Account) MarshalJSON() ([]byte, error) {
type Storage (line 145) | type Storage
FILE: w3types/state_test.go
function TestStateMerge (line 12) | func TestStateMerge(t *testing.T) {
FILE: w3vm/bench_test.go
function BenchmarkVM (line 27) | func BenchmarkVM(b *testing.B) {
function BenchmarkVMCall (line 111) | func BenchmarkVMCall(b *testing.B) {
function BenchmarkVMSnapshot (line 201) | func BenchmarkVMSnapshot(b *testing.B) {
FILE: w3vm/db.go
type db (line 21) | type db struct
method Has (line 37) | func (db *db) Has(addr common.Address, codeHash common.Hash) bool {
method Code (line 42) | func (db *db) Code(addr common.Address, codeHash common.Hash) ([]byte,...
method CodeSize (line 54) | func (db *db) CodeSize(addr common.Address, codeHash common.Hash) (int...
method Account (line 62) | func (db *db) Account(addr common.Address) (*types.StateAccount, error) {
method Storage (line 73) | func (db *db) Storage(addr common.Address, slot common.Hash) (common.H...
method Reader (line 91) | func (db *db) Reader(common.Hash) (state.Reader, error) { return db, n...
method OpenTrie (line 93) | func (db *db) OpenTrie(common.Hash) (state.Trie, error) { return fakeT...
method OpenStorageTrie (line 95) | func (db *db) OpenStorageTrie(common.Hash, common.Address, common.Hash...
method TrieDB (line 99) | func (*db) TrieDB() *triedb.Database { return fakeTrieDB }
method Snapshot (line 101) | func (*db) Snapshot() *snapshot.Tree { panic("not implemented") }
function newDB (line 25) | func newDB(fetcher Fetcher) *db {
FILE: w3vm/example_test.go
function ExampleVM_simpleTransfer (line 31) | func ExampleVM_simpleTransfer() {
function ExampleVM_fakeTokenBalance (line 62) | func ExampleVM_fakeTokenBalance() {
function ExampleVM_call (line 114) | func ExampleVM_call() {
function ExampleVM_callFunc (line 146) | func ExampleVM_callFunc() {
function ExampleVM_uniswapV3Swap (line 169) | func ExampleVM_uniswapV3Swap() {
function ExampleVM_prankZeroAddress (line 249) | func ExampleVM_prankZeroAddress() {
function ExampleVM_traceCalls (line 278) | func ExampleVM_traceCalls() {
function ExampleVM_traceAccessList (line 307) | func ExampleVM_traceAccessList() {
function ExampleVM_traceBlock (line 350) | func ExampleVM_traceBlock() {
function TestWETHDeposit (line 383) | func TestWETHDeposit(t *testing.T) {
function FuzzWETHDeposit (line 420) | func FuzzWETHDeposit(f *testing.F) {
function ExampleWETHBalanceSlot (line 463) | func ExampleWETHBalanceSlot() {
FILE: w3vm/fetcher.go
type Fetcher (line 32) | type Fetcher interface
type rpcFetcher (line 46) | type rpcFetcher struct
method Account (line 86) | func (f *rpcFetcher) Account(addr common.Address) (a *types.StateAccou...
method Code (line 135) | func (f *rpcFetcher) Code(codeHash common.Hash) ([]byte, error) {
method StorageAt (line 145) | func (f *rpcFetcher) StorageAt(addr common.Address, slot common.Hash) ...
method HeaderHash (line 172) | func (f *rpcFetcher) HeaderHash(blockNumber uint64) (common.Hash, erro...
method call (line 197) | func (f *rpcFetcher) call(calls ...w3types.RPCCaller) error {
method loadTestdataState (line 250) | func (f *rpcFetcher) loadTestdataState(chainID uint64) (err error) {
method storeTestdataState (line 312) | func (f *rpcFetcher) storeTestdataState(chainID uint64) (err error) {
function NewRPCFetcher (line 71) | func NewRPCFetcher(client *w3.Client, blockNumber *big.Int) Fetcher {
function newRPCFetcher (line 75) | func newRPCFetcher(client *w3.Client, blockNumber *big.Int) *rpcFetcher {
function NewTestingRPCFetcher (line 207) | func NewTestingRPCFetcher(tb testing.TB, chainID uint64, client *w3.Clie...
type storageKey (line 422) | type storageKey struct
type testdataState (line 429) | type testdataState
method Merge (line 431) | func (s testdataState) Merge(other testdataState) error {
type testdataAccount (line 445) | type testdataAccount struct
method codeHash (line 452) | func (a *testdataAccount) codeHash() common.Hash {
method Merge (line 459) | func (a *testdataAccount) Merge(other *testdataAccount) error {
type testdataContracts (line 490) | type testdataContracts
method Merge (line 492) | func (c testdataContracts) Merge(other testdataContracts) error {
type testdataHeaderHashes (line 506) | type testdataHeaderHashes
method Merge (line 508) | func (h testdataHeaderHashes) Merge(other testdataHeaderHashes) error {
function readTestdata (line 521) | func readTestdata(filename string, data any, onlyIfModifiedAfter time.Ti...
function writeTestdata (line 549) | func writeTestdata(filename string, data any) error {
function testdataPath (line 575) | func testdataPath(filename string) string {
FILE: w3vm/fetcher_test.go
function TestTestdataContractsMerge (line 16) | func TestTestdataContractsMerge(t *testing.T) {
function TestTestdataHeaderHashesMerge (line 79) | func TestTestdataHeaderHashesMerge(t *testing.T) {
function TestTestdataAccountMerge (line 142) | func TestTestdataAccountMerge(t *testing.T) {
function TestTestdataStateMerge (line 263) | func TestTestdataStateMerge(t *testing.T) {
FILE: w3vm/hooks/call_tracer.go
type CallTracerOptions (line 38) | type CallTracerOptions struct
method targetStyler (line 50) | func (opts *CallTracerOptions) targetStyler(addr common.Address) lipgl...
method showOp (line 61) | func (opts *CallTracerOptions) showOp(op byte, pc uint64, addr common....
method opStyler (line 68) | func (opts *CallTracerOptions) opStyler(op byte) lipgloss.Style {
function defaultTargetStyler (line 75) | func defaultTargetStyler(addr common.Address) lipgloss.Style {
function defaultOpStyler (line 84) | func defaultOpStyler(byte) lipgloss.Style {
function NewCallTracer (line 89) | func NewCallTracer(w io.Writer, opts *CallTracerOptions) *tracing.Hooks {
type callTracer (line 103) | type callTracer struct
method EnterHook (line 115) | func (c *callTracer) EnterHook(depth int, typ byte, from common.Addres...
method ExitHook (line 141) | func (c *callTracer) ExitHook(depth int, output []byte, gasUsed uint64...
method OpcodeHook (line 159) | func (c *callTracer) OpcodeHook(pc uint64, op byte, gas, cost uint64, ...
method OnLog (line 167) | func (c *callTracer) OnLog(log *types.Log) {
function renderIdent (line 173) | func renderIdent(callStack []call, styler func(addr common.Address) lipg...
function renderAddr (line 191) | func renderAddr(addr common.Address, styler func(addr common.Address) li...
function renderCallType (line 195) | func renderCallType(typ byte) string {
function renderValue (line 216) | func renderValue(decodeABI bool, val *big.Int) string {
function renderInput (line 226) | func renderInput(fn *w3.Func, isPrecompile bool, input []byte, styler fu...
function renderOutput (line 236) | func renderOutput(fn *w3.Func, output []byte, styler func(addr common.Ad...
function renderRevert (line 246) | func renderRevert(revertErr error, output []byte, decodeABI bool) string {
function renderRawInput (line 261) | func renderRawInput(input []byte, styler func(addr common.Address) lipgl...
function renderRawOutput (line 274) | func renderRawOutput(output []byte, styler func(addr common.Address) lip...
function renderWord (line 286) | func renderWord(word []byte, _ func(addr common.Address) lipgloss.Style)...
function renderAbiInput (line 295) | func renderAbiInput(fn *w3.Func, isPrecompile bool, input []byte, styler...
function renderAbiOutput (line 309) | func renderAbiOutput(fn *w3.Func, output []byte, styler func(addr common...
function renderAbiArgs (line 318) | func renderAbiArgs(args abi.Arguments, vals []any, styler func(addr comm...
function renderAbiTyp (line 329) | func renderAbiTyp(typ *abi.Type, name string, val any, styler func(addr ...
function renderOp (line 451) | func renderOp(op byte, style func(byte) lipgloss.Style, pc uint64, scope...
type call (line 478) | type call struct
function opAccessesStackElem (line 486) | func opAccessesStackElem(op byte, i int) bool {
FILE: w3vm/receipt.go
type Receipt (line 14) | type Receipt struct
method DecodeReturns (line 28) | func (r Receipt) DecodeReturns(returns ...any) error {
FILE: w3vm/util.go
function RandA (line 19) | func RandA() (addr common.Address) {
function WETHBalanceSlot (line 31) | func WETHBalanceSlot(addr common.Address) common.Hash {
function WETHAllowanceSlot (line 37) | func WETHAllowanceSlot(owner, spender common.Address) common.Hash {
function SoliditySlot (line 44) | func SoliditySlot(pos, key common.Hash) common.Hash {
function SoliditySlot2 (line 52) | func SoliditySlot2(pos, key0, key1 common.Hash) common.Hash {
function SoliditySlot3 (line 63) | func SoliditySlot3(pos, key0, key1, key2 common.Hash) common.Hash {
function VyperSlot (line 76) | func VyperSlot(pos, key common.Hash) common.Hash {
function VyperSlot2 (line 84) | func VyperSlot2(pos, key0, key1 common.Hash) common.Hash {
function VyperSlot3 (line 95) | func VyperSlot3(pos, key0, key1, key2 common.Hash) common.Hash {
function Slot (line 112) | func Slot(pos, key common.Hash) common.Hash {
function Slot2 (line 124) | func Slot2(pos, key0, key1 common.Hash) common.Hash {
function Slot3 (line 136) | func Slot3(pos, key0, key1, key2 common.Hash) common.Hash {
function zeroHashFunc (line 141) | func zeroHashFunc(uint64) common.Hash {
function ethBalance (line 150) | func ethBalance(addr common.Address, blockNumber *big.Int) w3types.RPCCa...
function ethHeaderHash (line 159) | func ethHeaderHash(blockNumber uint64) w3types.RPCCallerFactory[header] {
type header (line 166) | type header struct
function joinHooks (line 175) | func joinHooks(hooks []*tracing.Hooks) *tracing.Hooks {
FILE: w3vm/util_test.go
function TestWETHBalanceSlot (line 12) | func TestWETHBalanceSlot(t *testing.T) {
function TestWETHAllowanceSlot (line 37) | func TestWETHAllowanceSlot(t *testing.T) {
FILE: w3vm/vm.go
type VM (line 40) | type VM struct
method Apply (line 83) | func (vm *VM) Apply(msg *w3types.Message, hooks ...*tracing.Hooks) (*R...
method ApplyTx (line 88) | func (vm *VM) ApplyTx(tx *types.Transaction, hooks ...*tracing.Hooks) ...
method apply (line 96) | func (v *VM) apply(msg *w3types.Message, isCall bool, hooks *tracing.H...
method Call (line 179) | func (vm *VM) Call(msg *w3types.Message, hooks ...*tracing.Hooks) (*Re...
method CallFunc (line 196) | func (vm *VM) CallFunc(contract common.Address, f w3types.Func, args ....
method Nonce (line 218) | func (vm *VM) Nonce(addr common.Address) (uint64, error) {
method SetNonce (line 227) | func (vm *VM) SetNonce(addr common.Address, nonce uint64) {
method Balance (line 232) | func (vm *VM) Balance(addr common.Address) (*big.Int, error) {
method SetBalance (line 241) | func (vm *VM) SetBalance(addr common.Address, balance *big.Int) {
method Code (line 246) | func (vm *VM) Code(addr common.Address) ([]byte, error) {
method SetCode (line 255) | func (vm *VM) SetCode(addr common.Address, code []byte) {
method StorageAt (line 260) | func (vm *VM) StorageAt(addr common.Address, slot common.Hash) (common...
method SetStorageAt (line 269) | func (vm *VM) SetStorageAt(addr common.Address, slot, val common.Hash) {
method Snapshot (line 275) | func (vm *VM) Snapshot() *state.StateDB { return vm.db.Copy() }
method Rollback (line 278) | func (vm *VM) Rollback(snapshot *state.StateDB) {
method buildMessage (line 283) | func (v *VM) buildMessage(msg *w3types.Message, skipAccChecks bool) (*...
method Clone (line 419) | func (vm *VM) Clone() *VM {
function New (line 48) | func New(opts ...Option) (*VM, error) {
type CallFuncFactory (line 205) | type CallFuncFactory struct
method Returns (line 210) | func (cff *CallFuncFactory) Returns(returns ...any) error {
function newBlockContext (line 358) | func newBlockContext(config *params.ChainConfig, h *types.Header, getHas...
function defaultBlockContext (line 396) | func defaultBlockContext() *vm.BlockContext {
type options (line 431) | type options struct
method Signer (line 449) | func (opt *options) Signer() types.Signer {
method Init (line 456) | func (opts *options) Init() error {
function fetcherHashFunc (line 518) | func fetcherHashFunc(fetcher Fetcher) vm.GetHashFunc {
type Option (line 526) | type Option
function WithChainConfig (line 531) | func WithChainConfig(cfg *params.ChainConfig) Option {
function WithBlockContext (line 536) | func WithBlockContext(ctx *vm.BlockContext) Option {
function WithPrecompile (line 541) | func WithPrecompile(addr common.Address, contract vm.PrecompiledContract...
function WithState (line 554) | func WithState(state w3types.State) Option {
function WithStateDB (line 560) | func WithStateDB(db *state.StateDB) Option {
function WithNoBaseFee (line 568) | func WithNoBaseFee() Option {
function WithFork (line 578) | func WithFork(client *w3.Client, blockNumber *big.Int) Option {
function WithHeader (line 586) | func WithHeader(header *types.Header) Option {
function WithFetcher (line 591) | func WithFetcher(fetcher Fetcher) Option {
function WithTB (line 597) | func WithTB(tb testing.TB) Option {
function WithJumpDestCache (line 602) | func WithJumpDestCache(cache vm.JumpDestCache) Option {
FILE: w3vm/vm_test.go
function TestVMSetNonce (line 54) | func TestVMSetNonce(t *testing.T) {
function TestVMSetBalance (line 69) | func TestVMSetBalance(t *testing.T) {
function TestVMSetCode (line 84) | func TestVMSetCode(t *testing.T) {
function TestVMSetStorage (line 99) | func TestVMSetStorage(t *testing.T) {
function TestVMApply (line 114) | func TestVMApply(t *testing.T) {
function TestVMApply_Hook (line 298) | func TestVMApply_Hook(t *testing.T) {
function TestVMSnapshot (line 340) | func TestVMSnapshot(t *testing.T) {
function TestVMSnapshot_Logs (line 392) | func TestVMSnapshot_Logs(t *testing.T) {
function TestVMCall (line 566) | func TestVMCall(t *testing.T) {
function TestVMCallFunc (line 617) | func TestVMCallFunc(t *testing.T) {
function TestVM_Fetcher (line 640) | func TestVM_Fetcher(t *testing.T) {
function TestVM_BaseFee (line 674) | func TestVM_BaseFee(t *testing.T) {
type testFetcher (line 764) | type testFetcher struct
method Account (line 766) | func (f *testFetcher) Account(addr common.Address) (*types.StateAccoun...
method Code (line 770) | func (f *testFetcher) Code(codeHash common.Hash) ([]byte, error) {
method StorageAt (line 774) | func (f *testFetcher) StorageAt(addr common.Address, key common.Hash) ...
method HeaderHash (line 778) | func (f *testFetcher) HeaderHash(blockNumber uint64) (common.Hash, err...
function TestVMApply_Integration (line 782) | func TestVMApply_Integration(t *testing.T) {
function mustEncodeArgs (line 890) | func mustEncodeArgs(f w3types.Func, args ...any) []byte {
function BenchmarkTransferWETH9 (line 898) | func BenchmarkTransferWETH9(b *testing.B) {
function TestVMClone (line 977) | func TestVMClone(t *testing.T) {
type mockPrecompile (line 1113) | type mockPrecompile struct
method RequiredGas (line 1115) | func (m *mockPrecompile) RequiredGas(input []byte) uint64 { return 100 }
method Run (line 1116) | func (m *mockPrecompile) Run(input []byte) ([]byte, error) { return in...
method Name (line 1117) | func (m *mockPrecompile) Name() string { return "m...
function ptr (line 1119) | func ptr[T any](t T) *T { return &t }
Condensed preview — 263 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (7,958K chars).
[
{
"path": ".gitattributes",
"chars": 34,
"preview": "testdata/ linguist-generated=true\n"
},
{
"path": ".github/dependabot.yml",
"chars": 108,
"preview": "version: 2\nupdates:\n - package-ecosystem: \"gomod\"\n directory: \"/\"\n schedule:\n interval: \"daily\"\n"
},
{
"path": ".github/workflows/doc.yml",
"chars": 910,
"preview": "name: Doc\n\non:\n push:\n branches: [main]\n tags: [\"v*\"]\n pull_request:\n\njobs:\n build:\n name: Build\n runs-on"
},
{
"path": ".github/workflows/go.yml",
"chars": 1015,
"preview": "name: Go\n\non:\n push:\n branches:\n - main\n pull_request:\n\njobs:\n lint:\n name: Lint\n runs-on: ubuntu-lates"
},
{
"path": ".gitignore",
"chars": 47,
"preview": "# files\nLOCK\n\n# dirs\n.next/\nnode_modules/\nout/\n"
},
{
"path": "LICENSE",
"chars": 1066,
"preview": "MIT License\n\nCopyright (c) 2022 lmittmann\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\n"
},
{
"path": "README.md",
"chars": 15430,
"preview": "# `w3`: Enhanced Ethereum Integration for Go\n\n[](ht"
},
{
"path": "client.go",
"chars": 5727,
"preview": "/*\nPackage w3 is your toolbelt for integrating with Ethereum in Go. Closely linked\nto [go-ethereum], it provides an ergo"
},
{
"path": "client_test.go",
"chars": 7113,
"preview": "package w3_test\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"flag\"\n\t\"math/big\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/ethereum"
},
{
"path": "docs/components/DocLink.jsx",
"chars": 1037,
"preview": "import { Link } from 'nextra-theme-docs'\nimport { Code } from 'nextra/components'\n\nconst pkgNameToPath = {\n 'w3': 'gi"
},
{
"path": "docs/next.config.js",
"chars": 316,
"preview": "import nextra from 'nextra'\n\nconst withNextra = nextra({\n\ttheme: 'nextra-theme-docs',\n\tthemeConfig: './theme.config.jsx'"
},
{
"path": "docs/package.json",
"chars": 355,
"preview": "{\n\t\"type\": \"module\",\n\t\"scripts\": {\n\t\t\"dev\": \"next dev\",\n\t\t\"build\": \"next build\"\n\t},\n\t\"dependencies\": {\n\t\t\"next\": \"^14.2."
},
{
"path": "docs/pages/404.mdx",
"chars": 51,
"preview": "# Page Not Found\n\nGet back on track: [Homepage](/)\n"
},
{
"path": "docs/pages/_app.js",
"chars": 395,
"preview": "import './style.css'\nimport 'nextra-theme-docs/style.css'\nimport { Inter } from 'next/font/google'\n\nconst inter = Inter("
},
{
"path": "docs/pages/_meta.js",
"chars": 1887,
"preview": "export default {\n index: {\n title: 'Overview',\n display: 'hidden',\n theme: { breadcrumb: false, "
},
{
"path": "docs/pages/examples/_meta.js",
"chars": 161,
"preview": "export default {\n index: {\n title: 'Examples',\n display: 'hidden',\n theme: { breadcrumb: false, "
},
{
"path": "docs/pages/examples/index.mdx",
"chars": 3583,
"preview": "# Examples\n\n## `w3.Client` Examples\n\n* **Batch Fetch** 1000 blocks ([Playground](https://pkg.go.dev/github.com/lmittmann"
},
{
"path": "docs/pages/examples.mdx",
"chars": 0,
"preview": ""
},
{
"path": "docs/pages/helper-abi.mdx",
"chars": 7706,
"preview": "# ABI Bindings\n\nABI bindings allow the encoding and decoding of Smart Contract function calls or the decoding of events."
},
{
"path": "docs/pages/helper-utils.mdx",
"chars": 506,
"preview": "# Utils\n\nStatic addresses, hashes, bytes or integers can be parsed from (hex-)strings with the following utility functio"
},
{
"path": "docs/pages/index.mdx",
"chars": 2202,
"preview": "---\ndescription: 'w3: Enhanced Ethereum Integration for Go'\n---\n\n# `w3`: Enhanced Ethereum Integration for Go\n\n<div clas"
},
{
"path": "docs/pages/rpc-extension.mdx",
"chars": 2088,
"preview": "# Custom RPC Method Bindings\n\nCustom RPC method bindings can be created by implementing the <DocLink title=\"w3types.RPCC"
},
{
"path": "docs/pages/rpc-methods/_meta.js",
"chars": 131,
"preview": "export default {\n eth: 'eth',\n debug: 'debug',\n txpool: 'txpool',\n admin: 'admin',\n net: 'net',\n web3:"
},
{
"path": "docs/pages/rpc-methods/admin.mdx",
"chars": 1154,
"preview": "# `admin`-Namespace\n\nList of supported RPC methods for `w3.Client` in the `admin`-namespace.\n\n## `admin_addPeer`\n`AddPee"
},
{
"path": "docs/pages/rpc-methods/debug.mdx",
"chars": 933,
"preview": "# `debug`-Namespace\n\nList of supported RPC methods for `w3.Client` in the `debug`-namespace.\n\n## `debug_traceCall`\n`Trac"
},
{
"path": "docs/pages/rpc-methods/eth.mdx",
"chars": 6563,
"preview": "# `eth`-Namespace\n\nList of supported RPC methods for `w3.Client` in the `eth`-namespace.\n\n## `eth_blockNumber`\n`BlockNum"
},
{
"path": "docs/pages/rpc-methods/net.mdx",
"chars": 610,
"preview": "# `net`-Namespace\n\nList of supported RPC methods for `w3.Client` in the `net`-namespace.\n\n## `net_listening`\n`Listening`"
},
{
"path": "docs/pages/rpc-methods/txpool.mdx",
"chars": 769,
"preview": "# `txpool`-Namespace\n\nList of supported RPC methods for `w3.Client` in the `txpool`-namespace.\n\n## `txpool_content`\n`Con"
},
{
"path": "docs/pages/rpc-methods/web3.mdx",
"chars": 275,
"preview": "# `web3`-Namespace\n\nList of supported RPC methods for `w3.Client` in the `web3`-namespace.\n\n## `web3_clientVersion`\n`Cli"
},
{
"path": "docs/pages/rpc-methods.mdx",
"chars": 1135,
"preview": "# Methods\n\n`w3` supports most common RPC methods for Ethereum and other EVM chains. If you are in need of a method that "
},
{
"path": "docs/pages/rpc-overview.mdx",
"chars": 3196,
"preview": "# RPC Client\n\n<DocLink title=\"w3.Client\" /> is a blazing fast RPC client, built on top of `go-ethereum/rpc.Client`. It i"
},
{
"path": "docs/pages/style.css",
"chars": 1317,
"preview": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n@layer base {\n main {\n @apply dark:text-neutral-30"
},
{
"path": "docs/pages/vm-overview.mdx",
"chars": 7801,
"preview": "# VM\n\n<DocLink title=\"w3vm.VM\" /> is an easy-to-use Ethereum Virtual Machine (EVM), built on top of `go-ethereum`'s `vm."
},
{
"path": "docs/pages/vm-testing.mdx",
"chars": 5894,
"preview": "# Contract Testing\n\n`w3vm` can be used to test Smart Contracts in Go utilizing Go's handy testing and fuzzing features.\n"
},
{
"path": "docs/pages/vm-tracing.mdx",
"chars": 2196,
"preview": "# Tracing\n\nTracing can give detailed insights into the execution of EVM contracts. `w3vm.VM` supports tracing via `go‑et"
},
{
"path": "docs/postcss.config.cjs",
"chars": 130,
"preview": "module.exports = {\n plugins: {\n \"tailwindcss/nesting\": {},\n tailwindcss: {},\n autoprefixer: {},\n"
},
{
"path": "docs/public/_redirects",
"chars": 53,
"preview": "/vm /vm-overview\n/rpc /rpc-overview\n/abi /helper-abi\n"
},
{
"path": "docs/public/robots.txt",
"chars": 23,
"preview": "User-agent: *\nAllow: /\n"
},
{
"path": "docs/tailwind.config.js",
"chars": 183,
"preview": "module.exports = {\n\tcontent: [\n\t\t'./pages/**/*.{js,jsx,mdx}',\n\t\t'./components/**/*.{js,jsx}',\n\t\t'./theme.config.jsx'\n\t],"
},
{
"path": "docs/theme.config.jsx",
"chars": 2190,
"preview": "import Image from 'next/image'\nimport { useConfig } from 'nextra-theme-docs'\nimport { Callout, Cards, Steps } from 'next"
},
{
"path": "event.go",
"chars": 2991,
"preview": "package w3\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ethereum/go-ethereum/accounts/abi\"\n\t\"github.com/ethereum/go-ethereum/common\"\n\t"
},
{
"path": "event_test.go",
"chars": 7084,
"preview": "package w3_test\n\nimport (\n\t\"math/big\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/ethereum/go-ethereum/common\"\n\t\"github.com/ethe"
},
{
"path": "example_test.go",
"chars": 14660,
"preview": "package w3_test\n\nimport (\n\t\"crypto/ecdsa\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math/big\"\n\t\"time\"\n\n\t\"github.com/ethereum/go-ethereum/common"
},
{
"path": "func.go",
"chars": 4169,
"preview": "package w3\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/ethereum/go-ethereum/accounts/abi\"\n\t\"github.com/ethereum/go"
},
{
"path": "func_test.go",
"chars": 24655,
"preview": "package w3_test\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"math/big\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/ethereum/go-ethereum/common"
},
{
"path": "go.mod",
"chars": 2925,
"preview": "module github.com/lmittmann/w3\n\ngo 1.25.0\n\nrequire (\n\tgithub.com/charmbracelet/lipgloss v1.1.0\n\tgithub.com/ethereum/go-e"
},
{
"path": "go.sum",
"chars": 27146,
"preview": "github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=\ngithub.com/DataDog/zstd v1.4.5/go.mod h1:"
},
{
"path": "internal/abi/arguments.go",
"chars": 2673,
"preview": "package abi\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/ethereum/go-ethereum/accounts/abi\"\n\t\"github.com/lmittma"
},
{
"path": "internal/abi/arguments_test.go",
"chars": 21808,
"preview": "package abi\n\nimport (\n\t\"bytes\"\n\t\"math/big\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/ethereum/go-ethereum/accounts/"
},
{
"path": "internal/abi/copy.go",
"chars": 8062,
"preview": "package abi\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"math/big\"\n\t\"reflect\"\n\n\t\"github.com/ethereum/go-ethereum/accounts/abi\"\n\t\"github."
},
{
"path": "internal/abi/copy_test.go",
"chars": 7528,
"preview": "package abi\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/ethereum/go-ethereum/common\"\n\t\"github.com/go"
},
{
"path": "internal/abi/doc.go",
"chars": 74,
"preview": "/*\nPackage abi implements a Solidity ABI lexer and parser.\n*/\npackage abi\n"
},
{
"path": "internal/abi/lexer.go",
"chars": 7029,
"preview": "package abi\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unicode/utf8\"\n\n\t\"github.com/ethereum/go-ethereum/accounts/abi\"\n)\n\nt"
},
{
"path": "internal/abi/lexer_test.go",
"chars": 1547,
"preview": "package abi\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/google/go-cmp/cmp/cm"
},
{
"path": "internal/abi/parser.go",
"chars": 6891,
"preview": "package abi\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strconv\"\n\n\t\"github.com/ethereum/go-ethereum/accounts/abi\"\n)\n\nvar Err"
},
{
"path": "internal/abi/parser_test.go",
"chars": 19377,
"preview": "package abi\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/ethereum/go-ethereum/accounts/abi\"\n\t\"github."
},
{
"path": "internal/abi/tuple.go",
"chars": 6754,
"preview": "package abi\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"math/big\"\n\t\"reflect\"\n\t\"unicode\"\n\n\t\"github.com/ethereum/go-ethereum/accounts/abi"
},
{
"path": "internal/abi/tuple_test.go",
"chars": 7423,
"preview": "package abi\n\nimport (\n\t\"errors\"\n\t\"maps\"\n\t\"math/big\"\n\t\"reflect\"\n\t\"slices\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/ethereum/go"
},
{
"path": "internal/cmp.go",
"chars": 521,
"preview": "package internal\n\nimport (\n\t\"github.com/google/go-cmp/cmp\"\n)\n\n// EquateErrors returns a cmp.Option that can be used to c"
},
{
"path": "internal/cmp_test.go",
"chars": 1001,
"preview": "package internal\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n)\n\nfunc TestEquateErrors("
},
{
"path": "internal/crypto/keccak.go",
"chars": 1015,
"preview": "package crypto\n\nimport (\n\t\"sync\"\n\n\t\"github.com/ethereum/go-ethereum/common\"\n\t\"github.com/ethereum/go-ethereum/crypto\"\n)\n"
},
{
"path": "internal/fourbyte/events.go",
"chars": 2180,
"preview": "// Code generated by \"go generate\"; DO NOT EDIT.\npackage fourbyte\n\nimport \"github.com/lmittmann/w3\"\n\nvar events = map[[3"
},
{
"path": "internal/fourbyte/events.txt",
"chars": 535,
"preview": "Approval(address indexed owner, address indexed spender, uint256 value)\nBurn(address indexed sender, uint256 amount0, ui"
},
{
"path": "internal/fourbyte/fourbyte.go",
"chars": 974,
"preview": "//go:generate go run gen.go\n\npackage fourbyte\n\nimport (\n\t\"github.com/ethereum/go-ethereum/common\"\n\t\"github.com/lmittmann"
},
{
"path": "internal/fourbyte/funcs.go",
"chars": 66609,
"preview": "// Code generated by \"go generate\"; DO NOT EDIT.\npackage fourbyte\n\nimport \"github.com/lmittmann/w3\"\n\nvar functions = map"
},
{
"path": "internal/fourbyte/funcs.txt",
"chars": 41316,
"preview": "_BASE_TOKEN_()\taddress\n_QUOTE_TOKEN_()\taddress\nA()\tuint256\nA_precise()\tuint256\naccessor()\taddress\naccumulateReward(uint3"
},
{
"path": "internal/fourbyte/gen.go",
"chars": 5920,
"preview": "//go:build ignore\n\npackage main\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"fmt\"\n\t\"os\"\n\t\"slices\"\n\t\"strings\"\n\t\"sync\"\n\t\"text/template\"\n\n"
},
{
"path": "internal/hexutil/bytes.go",
"chars": 693,
"preview": "package hexutil\n\nimport (\n\t\"encoding/hex\"\n)\n\n// Bytes is a byte slice that marshals/unmarshals from a hex-encoded string"
},
{
"path": "internal/hexutil/bytes_test.go",
"chars": 1017,
"preview": "package hexutil_test\n\nimport (\n\t\"bytes\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/lmittmann/w3/internal/hexutil\"\n)\n\nvar bytesT"
},
{
"path": "internal/hexutil/hash.go",
"chars": 916,
"preview": "package hexutil\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\n\t\"github.com/ethereum/go-ethereum/common\"\n)\n\n// Hash is a wrapper ty"
},
{
"path": "internal/hexutil/hash_test.go",
"chars": 1223,
"preview": "package hexutil_test\n\nimport (\n\t\"math/big\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/ethereum/go-ethereum/common\"\n\t\"github.com"
},
{
"path": "internal/mod/root.go",
"chars": 359,
"preview": "package mod\n\nimport (\n\t\"os/exec\"\n\t\"strings\"\n)\n\n// Root contains the absolute path of the module root. Its value is empty"
},
{
"path": "internal/mod/root_test.go",
"chars": 223,
"preview": "package mod_test\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/lmittmann/w3/internal/mod\"\n)\n\nfunc TestModRoot(t *testing"
},
{
"path": "internal/module/factory.go",
"chars": 2166,
"preview": "package module\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"math/big\"\n\n\t\"github.com/ethereum/go-ethereum/common/hexutil\""
},
{
"path": "internal/module/util.go",
"chars": 346,
"preview": "package module\n\nimport (\n\t\"errors\"\n\t\"math/big\"\n\n\t\"github.com/ethereum/go-ethereum/common/hexutil\"\n)\n\nvar errNotFound = e"
},
{
"path": "internal/module/util_test.go",
"chars": 412,
"preview": "package module\n\nimport (\n\t\"math/big\"\n\t\"strconv\"\n\t\"testing\"\n)\n\nfunc TestBlockNumberArg(t *testing.T) {\n\ttests := []struct"
},
{
"path": "module/admin/admin.go",
"chars": 2194,
"preview": "/*\nPackage admin implements RPC API bindings for methods in the \"admin\" namespace.\n*/\npackage admin\n\nimport (\n\t\"math/big"
},
{
"path": "module/admin/admin_test.go",
"chars": 2887,
"preview": "package admin_test\n\nimport (\n\t\"math/big\"\n\t\"net\"\n\t\"testing\"\n\n\t\"github.com/ethereum/go-ethereum/p2p/enode\"\n\t\"github.com/et"
},
{
"path": "module/admin/testdata/add_peer.golden",
"chars": 263,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"admin_addPeer\",\"params\":[\"enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7"
},
{
"path": "module/admin/testdata/add_trusted_peer.golden",
"chars": 270,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"admin_addTrustedPeer\",\"params\":[\"enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa33"
},
{
"path": "module/admin/testdata/node_info.golden",
"chars": 864,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"admin_nodeInfo\",\"params\":[]}\n< {\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"enode\":\"enode://44"
},
{
"path": "module/admin/testdata/remove_peer.golden",
"chars": 266,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"admin_removePeer\",\"params\":[\"enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6"
},
{
"path": "module/admin/testdata/remove_trusted_peer.golden",
"chars": 273,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"admin_removeTrustedPeer\",\"params\":[\"enode://a979fb575495b8d6db44f750317d0f4622bf4c2a"
},
{
"path": "module/debug/call_trace.go",
"chars": 2390,
"preview": "package debug\n\nimport (\n\t\"encoding/json\"\n\t\"math/big\"\n\n\t\"github.com/ethereum/go-ethereum/common\"\n\t\"github.com/ethereum/go"
},
{
"path": "module/debug/call_trace_test.go",
"chars": 1432,
"preview": "package debug_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/lmittmann/w3\"\n\t\"github.com/lmittmann/w3/module/debug\"\n\t\"github.com"
},
{
"path": "module/debug/doc.go",
"chars": 100,
"preview": "/*\nPackage debug implements RPC API bindings for methods in the \"debug\" namespace.\n*/\npackage debug\n"
},
{
"path": "module/debug/testdata/traceCall.golden",
"chars": 468,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"debug_traceCall\",\"params\":[{\"from\":\"0x000000000000000000000000000000000000c0fe\",\"to\""
},
{
"path": "module/debug/testdata/traceCall_callTracer.golden",
"chars": 569,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"debug_traceCall\",\"params\":[{\"from\":\"0x000000000000000000000000000000000000c0fe\",\"to\""
},
{
"path": "module/debug/testdata/traceTx__1150000_0.golden",
"chars": 307,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"debug_traceTransaction\",\"params\":[\"0x38f299591902bfada359527fa6b9b597a959c41c6f72a3b"
},
{
"path": "module/debug/testdata/traceTx__12244000_0.golden",
"chars": 755,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"debug_traceTransaction\",\"params\":[\"0xac503dd98281d4d52c2043e297a6e684d175339a7ebf831"
},
{
"path": "module/debug/testdata/traceTx_revertReason.golden",
"chars": 464,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"debug_traceTransaction\",\"params\":[\"0x6ea1798a2d0d21db18d6e45ca00f230160b05f172f6022a"
},
{
"path": "module/debug/trace.go",
"chars": 4915,
"preview": "package debug\n\nimport (\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"math/big\"\n\n\t\"github.com/ethereum/go-ethereum/common\"\n\t"
},
{
"path": "module/debug/trace_test.go",
"chars": 1977,
"preview": "package debug_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/ethereum/go-ethereum/core/vm\"\n\t\"github.com/holiman/uint256\"\n\t\"gith"
},
{
"path": "module/eth/balance.go",
"chars": 576,
"preview": "package eth\n\nimport (\n\t\"math/big\"\n\n\t\"github.com/ethereum/go-ethereum/common\"\n\t\"github.com/lmittmann/w3/internal/module\"\n"
},
{
"path": "module/eth/balance_test.go",
"chars": 566,
"preview": "package eth_test\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/lmittmann/w3\"\n\t\"github.com/lmittmann/w3/module/eth\"\n\t\"gi"
},
{
"path": "module/eth/block.go",
"chars": 2740,
"preview": "package eth\n\nimport (\n\t\"encoding/json\"\n\t\"math/big\"\n\n\t\"github.com/ethereum/go-ethereum/common\"\n\t\"github.com/ethereum/go-e"
},
{
"path": "module/eth/block_number.go",
"chars": 343,
"preview": "package eth\n\nimport (\n\t\"math/big\"\n\n\t\"github.com/lmittmann/w3/internal/module\"\n\t\"github.com/lmittmann/w3/w3types\"\n)\n\n// B"
},
{
"path": "module/eth/block_number_test.go",
"chars": 348,
"preview": "package eth_test\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/lmittmann/w3\"\n\t\"github.com/lmittmann/w3/module/eth\"\n\t\"gi"
},
{
"path": "module/eth/block_test.go",
"chars": 14782,
"preview": "package eth_test\n\nimport (\n\t\"errors\"\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/ethereum/go-ethereum/common\"\n\t\"github.com/ethe"
},
{
"path": "module/eth/call.go",
"chars": 4293,
"preview": "package eth\n\nimport (\n\t\"encoding/json\"\n\t\"math/big\"\n\n\t\"github.com/ethereum/go-ethereum/common\"\n\t\"github.com/ethereum/go-e"
},
{
"path": "module/eth/call_test.go",
"chars": 2930,
"preview": "package eth_test\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/ethereum/go-ethereum/common\"\n\t\"github.com/ethereum/go-et"
},
{
"path": "module/eth/chain_id.go",
"chars": 297,
"preview": "package eth\n\nimport (\n\t\"github.com/lmittmann/w3/internal/module\"\n\t\"github.com/lmittmann/w3/w3types\"\n)\n\n// ChainID reques"
},
{
"path": "module/eth/chain_id_test.go",
"chars": 282,
"preview": "package eth_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/lmittmann/w3/module/eth\"\n\t\"github.com/lmittmann/w3/rpctest\"\n)\n\nfunc "
},
{
"path": "module/eth/code.go",
"chars": 561,
"preview": "package eth\n\nimport (\n\t\"math/big\"\n\n\t\"github.com/ethereum/go-ethereum/common\"\n\t\"github.com/lmittmann/w3/internal/module\"\n"
},
{
"path": "module/eth/code_test.go",
"chars": 375,
"preview": "package eth_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/lmittmann/w3\"\n\t\"github.com/lmittmann/w3/module/eth\"\n\t\"github.com/lmi"
},
{
"path": "module/eth/doc.go",
"chars": 94,
"preview": "/*\nPackage eth implements RPC API bindings for methods in the \"eth\" namespace.\n*/\npackage eth\n"
},
{
"path": "module/eth/gas_price.go",
"chars": 327,
"preview": "package eth\n\nimport (\n\t\"math/big\"\n\n\t\"github.com/lmittmann/w3/internal/module\"\n\t\"github.com/lmittmann/w3/w3types\"\n)\n\n// G"
},
{
"path": "module/eth/gas_price_test.go",
"chars": 339,
"preview": "package eth_test\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/lmittmann/w3\"\n\t\"github.com/lmittmann/w3/module/eth\"\n\t\"gi"
},
{
"path": "module/eth/gas_tip_cap.go",
"chars": 411,
"preview": "package eth\n\nimport (\n\t\"math/big\"\n\n\t\"github.com/lmittmann/w3/internal/module\"\n\t\"github.com/lmittmann/w3/w3types\"\n)\n\n// G"
},
{
"path": "module/eth/gas_tip_cap_test.go",
"chars": 343,
"preview": "package eth_test\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/lmittmann/w3\"\n\t\"github.com/lmittmann/w3/module/eth\"\n\t\"gi"
},
{
"path": "module/eth/get_logs.go",
"chars": 1703,
"preview": "package eth\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/ethereum/go-ethereum\"\n\t\"github.com/ethereum/go-ethereum/core/types\"\n\t\"github."
},
{
"path": "module/eth/get_logs_test.go",
"chars": 2484,
"preview": "package eth_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/ethereum/go-ethereum\"\n\t\"github.com/ethereum/go-ethereum/common\"\n\t\"gi"
},
{
"path": "module/eth/storage_at.go",
"chars": 716,
"preview": "package eth\n\nimport (\n\t\"math/big\"\n\n\t\"github.com/ethereum/go-ethereum/common\"\n\t\"github.com/lmittmann/w3/internal/hexutil\""
},
{
"path": "module/eth/storage_at_test.go",
"chars": 865,
"preview": "package eth_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/ethereum/go-ethereum/common\"\n\t\"github.com/lmittmann/w3\"\n\t\"github.com"
},
{
"path": "module/eth/subscribe.go",
"chars": 1096,
"preview": "package eth\n\nimport (\n\t\"github.com/ethereum/go-ethereum\"\n\t\"github.com/ethereum/go-ethereum/core/types\"\n\t\"github.com/lmit"
},
{
"path": "module/eth/syncing.go",
"chars": 535,
"preview": "package eth\n\nimport (\n\t\"github.com/lmittmann/w3/internal/module\"\n\t\"github.com/lmittmann/w3/w3types\"\n)\n\n// Syncing reques"
},
{
"path": "module/eth/syncing_test.go",
"chars": 373,
"preview": "package eth_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/lmittmann/w3/module/eth\"\n\t\"github.com/lmittmann/w3/rpctest\"\n)\n\nfunc "
},
{
"path": "module/eth/testdata/block_number.golden",
"chars": 99,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_blockNumber\"}\n< {\"jsonrpc\":\"2.0\",\"id\":1,\"result\":\"0xc0fe\"}\n"
},
{
"path": "module/eth/testdata/block_transaction_count_by_hash__0x00.golden",
"chars": 194,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getBlockTransactionCountByHash\",\"params\":[\"0x00000000000000000000000000000000000"
},
{
"path": "module/eth/testdata/block_transaction_count_by_hash__15050000.golden",
"chars": 196,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getBlockTransactionCountByHash\",\"params\":[\"0xc43d35f6a64f8a64f046c8deb4069572d62"
},
{
"path": "module/eth/testdata/block_transaction_count_by_number__15050000.golden",
"chars": 140,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getBlockTransactionCountByNumber\",\"params\":[\"0xe5a510\"]}\n< {\"jsonrpc\":\"2.0\",\"id\""
},
{
"path": "module/eth/testdata/call_func.golden",
"chars": 308,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_call\",\"params\":[{\"to\":\"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\",\"data\":\"0x70a"
},
{
"path": "module/eth/testdata/call_func__overrides.golden",
"chars": 509,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_call\",\"params\":[{\"to\":\"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\",\"data\":\"0x70a"
},
{
"path": "module/eth/testdata/chain_id.golden",
"chars": 92,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_chainId\"}\n< {\"jsonrpc\":\"2.0\",\"id\":1,\"result\":\"0x1\"}\n"
},
{
"path": "module/eth/testdata/create_access_list.golden",
"chars": 429,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_createAccessList\",\"params\":[{\"to\":\"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\",\""
},
{
"path": "module/eth/testdata/estimate_gas.golden",
"chars": 255,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_estimateGas\",\"params\":[{\"to\":\"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\",\"data\""
},
{
"path": "module/eth/testdata/gas_price.golden",
"chars": 96,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_gasPrice\"}\n< {\"jsonrpc\":\"2.0\",\"id\":1,\"result\":\"0xc0fe\"}\n"
},
{
"path": "module/eth/testdata/gas_tip_cap.golden",
"chars": 108,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_maxPriorityFeePerGas\"}\n< {\"jsonrpc\":\"2.0\",\"id\":1,\"result\":\"0xc0fe\"}\n"
},
{
"path": "module/eth/testdata/get_balance.golden",
"chars": 174,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getBalance\",\"params\":[\"0x000000000000000000000000000000000000c0fe\",\"latest\"]}\n< "
},
{
"path": "module/eth/testdata/get_balance__at_block.golden",
"chars": 172,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getBalance\",\"params\":[\"0x000000000000000000000000000000000000c0fe\",\"0xff\"]}\n< {\""
},
{
"path": "module/eth/testdata/get_block_by_hash__0x00.golden",
"chars": 183,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getBlockByHash\",\"params\":[\"0x000000000000000000000000000000000000000000000000000"
},
{
"path": "module/eth/testdata/get_block_by_hash__1.golden",
"chars": 1610,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getBlockByHash\",\"params\":[\"0x88e96d4537bea4d9c05d12549907b32561d3bf31f45aae734cd"
},
{
"path": "module/eth/testdata/get_block_by_hash__12965000.golden",
"chars": 19537,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getBlockByHash\",\"params\":[\"0x9b83c12c69edb74f6c8dd5d052765c1adf940e320bd1291696e"
},
{
"path": "module/eth/testdata/get_block_by_hash__18000000.golden",
"chars": 1896,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getBlockByHash\",\"params\":[\"0x95b198e154acbfc64109dfd22d8224fe927fd8dfdedfae01587"
},
{
"path": "module/eth/testdata/get_block_by_hash__46147.golden",
"chars": 2160,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getBlockByHash\",\"params\":[\"0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db"
},
{
"path": "module/eth/testdata/get_block_by_number__1.golden",
"chars": 1549,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getBlockByNumber\",\"params\":[\"0x1\",true]}\n< {\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"di"
},
{
"path": "module/eth/testdata/get_block_by_number__12965000.golden",
"chars": 19481,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getBlockByNumber\",\"params\":[\"0xc5d488\",false]}\n< {\"jsonrpc\":\"2.0\",\"id\":1,\"result"
},
{
"path": "module/eth/testdata/get_block_by_number__46147.golden",
"chars": 2102,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getBlockByNumber\",\"params\":[\"0xb443\",true]}\n< {\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{"
},
{
"path": "module/eth/testdata/get_block_by_number__999999999.golden",
"chars": 129,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getBlockByNumber\",\"params\":[\"0x3b9ac9ff\",true]}\n< {\"jsonrpc\":\"2.0\",\"id\":1,\"resul"
},
{
"path": "module/eth/testdata/get_block_receipts.golden",
"chars": 1694,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getBlockReceipts\",\"params\":[\"0xc0fe\"]}\n< {\"jsonrpc\":\"2.0\",\"id\":1,\"result\":[{\"blo"
},
{
"path": "module/eth/testdata/get_code.golden",
"chars": 164,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getCode\",\"params\":[\"0x000000000000000000000000000000000000c0de\",\"latest\"]}\n< {\"j"
},
{
"path": "module/eth/testdata/get_logs.golden",
"chars": 1563,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getLogs\",\"params\":[{\"fromBlock\":\"0x989680\",\"toBlock\":\"0x98bd90\",\"topics\":[[\"0x0d"
},
{
"path": "module/eth/testdata/get_storage_at.golden",
"chars": 294,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getStorageAt\",\"params\":[\"0x000000000000000000000000000000000000c0de\",\"0x00000000"
},
{
"path": "module/eth/testdata/get_storage_at__number.golden",
"chars": 232,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getStorageAt\",\"params\":[\"0x000000000000000000000000000000000000c0de\",\"0x00000000"
},
{
"path": "module/eth/testdata/get_transaction_by_block_hash_and_index.golden",
"chars": 997,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getTransactionByBlockHashAndIndex\",\"params\":[\"0xa32d159805750cbe428b799a49b85dcb"
},
{
"path": "module/eth/testdata/get_transaction_by_block_hash_and_index__300.golden",
"chars": 205,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getTransactionByBlockHashAndIndex\",\"params\":[\"0xa32d159805750cbe428b799a49b85dcb"
},
{
"path": "module/eth/testdata/get_transaction_by_block_number_and_index.golden",
"chars": 941,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getTransactionByBlockNumberAndIndex\",\"params\":[\"0xc5d489\",\"0x62\"]}\n< {\"jsonrpc\":"
},
{
"path": "module/eth/testdata/get_transaction_by_hash__0x00.golden",
"chars": 184,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getTransactionByHash\",\"params\":[\"0x000000000000000000000000000000000000000000000"
},
{
"path": "module/eth/testdata/get_transaction_by_hash__type0.golden",
"chars": 745,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getTransactionByHash\",\"params\":[\"0x2ecd08e86079f08cfc27c326aa01b1c8d62f288d59611"
},
{
"path": "module/eth/testdata/get_transaction_by_hash__type2.golden",
"chars": 977,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getTransactionByHash\",\"params\":[\"0xed382cb554ad10e94921d263a56c670669d6c380bbdac"
},
{
"path": "module/eth/testdata/get_transaction_count.golden",
"chars": 169,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getTransactionCount\",\"params\":[\"0x000000000000000000000000000000000000c0fe\",\"lat"
},
{
"path": "module/eth/testdata/get_transaction_receipt.golden",
"chars": 1757,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getTransactionReceipt\",\"params\":[\"0xed382cb554ad10e94921d263a56c670669d6c380bbda"
},
{
"path": "module/eth/testdata/get_transaction_receipt_0x00.golden",
"chars": 185,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getTransactionReceipt\",\"params\":[\"0x00000000000000000000000000000000000000000000"
},
{
"path": "module/eth/testdata/send_raw_transaction.golden",
"chars": 546,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_sendRawTransaction\",\"params\":[\"0x02f8b301820105850712ca0300850789ff970082b886944"
},
{
"path": "module/eth/testdata/syncing__false.golden",
"chars": 104,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_syncing\",\"params\":[]}\n< {\"jsonrpc\":\"2.0\",\"id\":1,\"result\":false}\n"
},
{
"path": "module/eth/testdata/syncing__true.golden",
"chars": 455,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_syncing\",\"params\":[]}\n< {\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"currentBlock\":\"0x3cf5"
},
{
"path": "module/eth/testdata/uncle_by_hash_and_index__15050036.golden",
"chars": 1620,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getUncleByBlockHashAndIndex\",\"params\":[\"0x7a98a492c1288a8451905bc665cb28d45fbdf8"
},
{
"path": "module/eth/testdata/uncle_by_hash_and_index__15050036_1.golden",
"chars": 197,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getUncleByBlockHashAndIndex\",\"params\":[\"0x7a98a492c1288a8451905bc665cb28d45fbdf8"
},
{
"path": "module/eth/testdata/uncle_by_number_and_index__15050036.golden",
"chars": 1564,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getUncleByBlockNumberAndIndex\",\"params\":[\"0xe5a534\",\"0x0\"]}\n< {\"jsonrpc\":\"2.0\",\""
},
{
"path": "module/eth/testdata/uncle_count_by_hash__15050036.golden",
"chars": 189,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getUncleCountByBlockHash\",\"params\":[\"0x7a98a492c1288a8451905bc665cb28d45fbdf8913"
},
{
"path": "module/eth/testdata/uncle_count_by_number__15050036.golden",
"chars": 133,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getUncleCountByBlockNumber\",\"params\":[\"0xe5a534\"]}\n< {\"jsonrpc\":\"2.0\",\"id\":1,\"re"
},
{
"path": "module/eth/tx.go",
"chars": 2846,
"preview": "package eth\n\nimport (\n\t\"math/big\"\n\n\t\"github.com/ethereum/go-ethereum/common\"\n\t\"github.com/ethereum/go-ethereum/common/he"
},
{
"path": "module/eth/tx_test.go",
"chars": 7215,
"preview": "package eth_test\n\nimport (\n\t\"fmt\"\n\t\"math/big\"\n\t\"sync/atomic\"\n\t\"testing\"\n\n\t\"github.com/ethereum/go-ethereum/common\"\n\t\"git"
},
{
"path": "module/eth/uncle.go",
"chars": 1575,
"preview": "package eth\n\nimport (\n\t\"math/big\"\n\n\t\"github.com/ethereum/go-ethereum/common\"\n\t\"github.com/ethereum/go-ethereum/common/he"
},
{
"path": "module/eth/uncle_test.go",
"chars": 3270,
"preview": "package eth_test\n\nimport (\n\t\"errors\"\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/ethereum/go-ethereum/core/types\"\n\t\"github.com/"
},
{
"path": "module/net/net.go",
"chars": 740,
"preview": "/*\nPackage net implements RPC API bindings for methods in the \"net\" namespace.\n*/\npackage net\n\nimport (\n\t\"github.com/lmi"
},
{
"path": "module/net/net_test.go",
"chars": 624,
"preview": "package net_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/lmittmann/w3/module/net\"\n\t\"github.com/lmittmann/w3/rpctest\"\n)\n\nfunc "
},
{
"path": "module/net/testdata/listening.golden",
"chars": 105,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"net_listening\",\"params\":[]}\n< {\"jsonrpc\":\"2.0\",\"id\":1,\"result\":true}\n"
},
{
"path": "module/net/testdata/peer_count.golden",
"chars": 103,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"net_peerCount\",\"params\":[]}\n< {\"jsonrpc\":\"2.0\",\"id\":1,\"result\":10}\n"
},
{
"path": "module/net/testdata/version.golden",
"chars": 100,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"net_version\",\"params\":[]}\n< {\"jsonrpc\":\"2.0\",\"id\":1,\"result\":1}\n"
},
{
"path": "module/txpool/content.go",
"chars": 2475,
"preview": "package txpool\n\nimport (\n\t\"encoding/json\"\n\t\"sort\"\n\n\t\"github.com/ethereum/go-ethereum/common\"\n\t\"github.com/ethereum/go-et"
},
{
"path": "module/txpool/content_test.go",
"chars": 4341,
"preview": "package txpool_test\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/ethereum/go-ethereum/common\"\n\t\"github.com/ethereum/go"
},
{
"path": "module/txpool/doc.go",
"chars": 103,
"preview": "/*\nPackage txpool implements RPC API bindings for methods in the \"txpool\" namespace.\n*/\npackage txpool\n"
},
{
"path": "module/txpool/status.go",
"chars": 797,
"preview": "package txpool\n\nimport (\n\t\"encoding/json\"\n\n\t\"github.com/ethereum/go-ethereum/common/hexutil\"\n\t\"github.com/lmittmann/w3/i"
},
{
"path": "module/txpool/status_test.go",
"chars": 348,
"preview": "package txpool_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/lmittmann/w3/module/txpool\"\n\t\"github.com/lmittmann/w3/rpctest\"\n)\n"
},
{
"path": "module/txpool/testdata/content.golden",
"chars": 2962,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"txpool_content\"}\n< {\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"pending\":{\"0x000454307bB96E303"
},
{
"path": "module/txpool/testdata/contentFrom.golden",
"chars": 756,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"txpool_contentFrom\",\"params\":[\"0x1ba4ca9ac6ff4cf192c11e8c1624563f302caa87\"]}\n< {\"jso"
},
{
"path": "module/txpool/testdata/status.golden",
"chars": 121,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"txpool_status\"}\n< {\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"pending\":\"0xa\",\"queued\":\"0x7\"}}"
},
{
"path": "module/web3/testdata/client_version.golden",
"chars": 100,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"web3_clientVersion\"}\n< {\"jsonrpc\":\"2.0\",\"id\":1,\"result\":\"Geth\"}\n"
},
{
"path": "module/web3/testdata/client_version__err.golden",
"chars": 182,
"preview": "> {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"web3_clientVersion\"}\n< {\"jsonrpc\":\"2.0\",\"id\":1,\"error\":{\"code\":-32601,\"message\":\"the"
},
{
"path": "module/web3/web3.go",
"chars": 371,
"preview": "/*\nPackage web3 implements RPC API bindings for methods in the \"web3\" namespace.\n*/\npackage web3\n\nimport (\n\t\"github.com/"
},
{
"path": "module/web3/web3_test.go",
"chars": 502,
"preview": "package web3_test\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/lmittmann/w3/module/web3\"\n\t\"github.com/lmittmann/w3/rpcte"
},
{
"path": "rpctest/server.go",
"chars": 2646,
"preview": "// Package rpctest provides utilities for testing RPC methods.\npackage rpctest\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"io\"\n\t\"net/h"
},
{
"path": "rpctest/test_case.go",
"chars": 1755,
"preview": "package rpctest\n\nimport (\n\t\"fmt\"\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/ethereum/go-ethereum/core/types\"\n\t\"github.com/goog"
},
{
"path": "testdata/w3vm/1_12243997.json",
"chars": 150928,
"preview": "{\n\t\"0x0000000000000000000000000000000000000002\": {\n\t\t\"nonce\": \"0x0\",\n\t\t\"balance\": \"0x261bf27028cd820\"\n\t},\n\t\"0x0000000000"
},
{
"path": "testdata/w3vm/1_12243998.json",
"chars": 132165,
"preview": "{\n\t\"0x0000000000000000000000000000000000000001\": {\n\t\t\"nonce\": \"0x0\",\n\t\t\"balance\": \"0xb9d9fabaebe71e25\"\n\t},\n\t\"0x00000000c"
},
{
"path": "testdata/w3vm/1_12243999.json",
"chars": 136964,
"preview": "{\n\t\"0x0000000000000000000000000000000000000001\": {\n\t\t\"nonce\": \"0x0\",\n\t\t\"balance\": \"0xb9d9fabaebe71e25\"\n\t},\n\t\"0x000000000"
},
{
"path": "testdata/w3vm/1_12244000.json",
"chars": 101428,
"preview": "{\n\t\"0x0000000000000000000000000000000000000001\": {\n\t\t\"nonce\": \"0x0\",\n\t\t\"balance\": \"0xb9d9fabaebe71e25\"\n\t},\n\t\"0x0000a1c00"
},
{
"path": "testdata/w3vm/1_12964997.json",
"chars": 168027,
"preview": "{\n\t\"0x0000000000000000000000000000000000000001\": {\n\t\t\"nonce\": \"0x0\",\n\t\t\"balance\": \"0xb9e06356c739eb57\"\n\t},\n\t\"0x000000000"
},
{
"path": "testdata/w3vm/1_12964998.json",
"chars": 176031,
"preview": "{\n\t\"0x0000000000000000000000000000000000000001\": {\n\t\t\"nonce\": \"0x0\",\n\t\t\"balance\": \"0xb9e06356c739eb57\"\n\t},\n\t\"0x000000000"
},
{
"path": "testdata/w3vm/1_12964999.json",
"chars": 297490,
"preview": "{\n\t\"0x0000000000000000000000000000000000000001\": {\n\t\t\"nonce\": \"0x0\",\n\t\t\"balance\": \"0xb9e06356c739eb57\"\n\t},\n\t\"0x000000000"
},
{
"path": "testdata/w3vm/1_12965000.json",
"chars": 225519,
"preview": "{\n\t\"0x0000000000000000000000000000000000000001\": {\n\t\t\"nonce\": \"0x0\",\n\t\t\"balance\": \"0xb9e06356c739eb57\"\n\t},\n\t\"0x000000000"
},
{
"path": "testdata/w3vm/1_13772997.json",
"chars": 113018,
"preview": "{\n\t\"0x0000000000000000000000000000000000000001\": {\n\t\t\"nonce\": \"0x0\",\n\t\t\"balance\": \"0xbd251d6b80b88add\"\n\t},\n\t\"0x000000000"
},
{
"path": "testdata/w3vm/1_13772998.json",
"chars": 257051,
"preview": "{\n\t\"0x0000000000000000000000000000000000000001\": {\n\t\t\"nonce\": \"0x0\",\n\t\t\"balance\": \"0xbd251d6b80b88add\"\n\t},\n\t\"0x000000000"
},
{
"path": "testdata/w3vm/1_13772999.json",
"chars": 168610,
"preview": "{\n\t\"0x0000000000000000000000000000000000000001\": {\n\t\t\"nonce\": \"0x0\",\n\t\t\"balance\": \"0xbd251d6b80b88add\"\n\t},\n\t\"0x000000000"
},
{
"path": "testdata/w3vm/1_13773000.json",
"chars": 277251,
"preview": "{\n\t\"0x0000000000000000000000000000000000000001\": {\n\t\t\"nonce\": \"0x0\",\n\t\t\"balance\": \"0xbd251d6b80b88add\"\n\t},\n\t\"0x000000000"
},
{
"path": "testdata/w3vm/1_15049997.json",
"chars": 288233,
"preview": "{\n\t\"0x0000000000000000000000000000000000000001\": {\n\t\t\"nonce\": \"0x0\",\n\t\t\"balance\": \"0xdd105b3be81e8add\"\n\t},\n\t\"0x000000000"
},
{
"path": "testdata/w3vm/1_15049998.json",
"chars": 121694,
"preview": "{\n\t\"0x0000000000000000000000000000000000000001\": {\n\t\t\"nonce\": \"0x0\",\n\t\t\"balance\": \"0xdd105b3be81e8add\"\n\t},\n\t\"0x000000000"
},
{
"path": "testdata/w3vm/1_15049999.json",
"chars": 31986,
"preview": "{\n\t\"0x0000000000000000000000000000000000000001\": {\n\t\t\"nonce\": \"0x0\",\n\t\t\"balance\": \"0xdd105b3be81e8add\"\n\t},\n\t\"0x000000000"
},
{
"path": "testdata/w3vm/1_15050000.json",
"chars": 85447,
"preview": "{\n\t\"0x0000000000000000000000000000000000000001\": {\n\t\t\"nonce\": \"0x0\",\n\t\t\"balance\": \"0xdd105b3be81e8add\"\n\t},\n\t\"0x000000000"
}
]
// ... and 63 more files (download for full content)
About this extraction
This page contains the full source code of the lmittmann/w3 GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 263 files (76.8 MB), approximately 1.8M tokens, and a symbol index with 583 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.