From ba4a244fbc6d99ba7618900cdfdeb25684763d7e Mon Sep 17 00:00:00 2001 From: lmittmann Date: Thu, 1 Feb 2024 09:51:24 +0100 Subject: [PATCH 01/36] updated intro --- README.md | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 9ba25451..c1da544a 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,38 @@ -# w3 +# `w3`: Enhanced Ethereum Integration for Go [![Go Reference](https://pkg.go.dev/badge/github.com/lmittmann/w3.svg)](https://pkg.go.dev/github.com/lmittmann/w3) [![Go Report Card](https://goreportcard.com/badge/github.com/lmittmann/w3)](https://goreportcard.com/report/github.com/lmittmann/w3) [![Coverage Status](https://coveralls.io/repos/github/lmittmann/w3/badge.svg?branch=main)](https://coveralls.io/github/lmittmann/w3?branch=main) [![Latest Release](https://img.shields.io/github/v/release/lmittmann/w3)](https://github.com/lmittmann/w3/releases) +W3 Gopher -W3 Gopher +`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) + + +## Getting Started + +### RPC Client + +### VM + +### ABI Bindings + +### Utils + + Package `w3` implements a blazing fast and modular Ethereum JSON RPC client with first-class ABI support. @@ -35,13 +62,6 @@ Call_Block100 6.89s ± 7% 1.94s ±11% -71.77% (p=0.000 n=24+23) -## Install - -``` -go get github.com/lmittmann/w3 -``` - - ## Getting Started > **Note** From 70f225c7ba13eeb81dbeb5816c1d8a338133e2db Mon Sep 17 00:00:00 2001 From: lmittmann Date: Fri, 2 Feb 2024 17:09:10 +0100 Subject: [PATCH 02/36] use non breaking hyphen --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c1da544a..863c9af1 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![Latest Release](https://img.shields.io/github/v/release/lmittmann/w3)](https://github.com/lmittmann/w3/releases) W3 Gopher -`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**. +`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**. ``` From c8a7ab470fb7e5e40e3a086510780790dcbf6add Mon Sep 17 00:00:00 2001 From: lmittmann Date: Sun, 4 Feb 2024 14:30:27 +0100 Subject: [PATCH 03/36] updated RPC section --- README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/README.md b/README.md index 863c9af1..e2a61f51 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,34 @@ go get github.com/lmittmann/w3 ### RPC Client +`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. + + +```go +// 1. Connect to an RPC endpoint +client, err := w3.Dial("https://rpc.ankr.com/eth") +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. + ### VM ### ABI Bindings From 347a533aa2b4c535a73cac824a48eb77c1609307 Mon Sep 17 00:00:00 2001 From: lmittmann Date: Sun, 4 Feb 2024 20:31:14 +0100 Subject: [PATCH 04/36] added VM section --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index e2a61f51..7ebd03aa 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,18 @@ if err := client.Call( ### VM +`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. + +```go +// 1. Create a VM that forks the Mainnet state from the latest block +vm, err := w3vm.New( + w3vm.WithFork(client, nil), +) +if err != nil { + // handle error +} +``` + ### ABI Bindings ### Utils From 664c265c9d0152aca37b41760686882ff8389ec0 Mon Sep 17 00:00:00 2001 From: lmittmann Date: Sun, 4 Feb 2024 20:32:31 +0100 Subject: [PATCH 05/36] changed code ident --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 7ebd03aa..9fd757b8 100644 --- a/README.md +++ b/README.md @@ -33,20 +33,20 @@ go get github.com/lmittmann/w3 // 1. Connect to an RPC endpoint client, err := w3.Dial("https://rpc.ankr.com/eth") if err != nil { - // handle error + // handle error } defer client.Close() // 2. Make a batch request var ( - balance big.Int - nonce uint64 + balance big.Int + nonce uint64 ) if err := client.Call( - eth.Balance(addr, nil).Returns(&balance), - eth.Nonce(addr, nil).Returns(&nonce), + eth.Balance(addr, nil).Returns(&balance), + eth.Nonce(addr, nil).Returns(&nonce), ); err != nil { - // handle error + // handle error } ``` From f0e0c1709e30992785058d09c3640b5952ef29ee Mon Sep 17 00:00:00 2001 From: lmittmann Date: Sun, 4 Feb 2024 20:34:25 +0100 Subject: [PATCH 06/36] added links --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9fd757b8..a0a4c01d 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ go get github.com/lmittmann/w3 ### RPC Client -`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. +[`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. ```go @@ -56,7 +56,7 @@ if err := client.Call( ### VM -`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. +[`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. ```go // 1. Create a VM that forks the Mainnet state from the latest block From b8ccb99e82a0107bee7a7f54c876f191312b255f Mon Sep 17 00:00:00 2001 From: lmittmann Date: Sun, 3 Mar 2024 15:55:48 +0100 Subject: [PATCH 07/36] updated client example --- README.md | 1 + client_test.go | 24 ++++++++++++++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index a0a4c01d..84c6a751 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ if err := client.Call( // handle error } ``` +[Playground ↗](#https://pkg.go.dev/github.com/lmittmann/w3#example-Client) > [!NOTE] > #### why send batch requests? diff --git a/client_test.go b/client_test.go index 43f7ddf3..a46df48c 100644 --- a/client_test.go +++ b/client_test.go @@ -34,17 +34,29 @@ var ( `< [{"jsonrpc":"2.0","id":1,"result":"0x1"},{"jsonrpc":"2.0","id":2,"result":"0x1"}]` ) -func ExampleDial() { +func ExampleClient() { + addr := w3.A("0x0000000000000000000000000000000000000000") + + // 1. Connect to an RPC endpoint client, err := w3.Dial("https://rpc.ankr.com/eth") if err != nil { - // ... + // handle error } defer client.Close() -} -func ExampleMustDial() { - client := w3.MustDial("https://rpc.ankr.com/eth") - 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 + } + + fmt.Printf("balance: %s\nnonce: %d\n", w3.FromWei(&balance, 18), nonce) } func ExampleClient_Call() { From ffbd4cd0fc5c9f54258044093ff2ea364c6a99df Mon Sep 17 00:00:00 2001 From: lmittmann Date: Sun, 3 Mar 2024 22:56:10 +0100 Subject: [PATCH 08/36] added VM example --- README.md | 39 +++++++++++++++++++++-- w3vm/vm_test.go | 85 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 84c6a751..8a427f39 100644 --- a/README.md +++ b/README.md @@ -62,12 +62,47 @@ if err := client.Call( ```go // 1. Create a VM that forks the Mainnet state from the latest block vm, err := w3vm.New( - w3vm.WithFork(client, nil), + w3vm.WithFork(client, nil), + w3vm.WithNoBaseFee(), + w3vm.WithState(w3types.State{ + // give the EOA a fake WBNB balance and approval of the router + addrWETH: { + Storage: map[common.Hash]common.Hash{ + w3vm.WETHBalanceSlot(addrEOA): common.BigToHash(w3.I("1 ether")), + w3vm.WETHAllowanceSlot(addrEOA, addrRouter): common.BigToHash(w3.I("1 ether")), + }, + }, + }), ) if err != nil { - // handle error + // handle error +} + +// 2. Simulate a UniSwap v2 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. Print the output amount +var amountOut *big.Int +if err := receipt.DecodeReturns(&amountOut); err != nil { + // handle error } ``` +[Playground ↗](#https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM) ### ABI Bindings diff --git a/w3vm/vm_test.go b/w3vm/vm_test.go index d5aec9c9..17a3bd66 100644 --- a/w3vm/vm_test.go +++ b/w3vm/vm_test.go @@ -5,9 +5,11 @@ import ( "errors" "fmt" "math/big" + "slices" "strconv" "strings" "testing" + "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" @@ -537,4 +539,87 @@ func BenchmarkTransferWETH9(b *testing.B) { }) } +func ExampleVM() { + var ( + addrEOA = w3.A("0x000000000000000000000000000000000000c0Fe") + addrWETH = w3.A("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2") + addrUNI = w3.A("0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984") + addrRouter = w3.A("0xE592427A0AEce92De3Edee1F18E0157C05861564") + + funcExactInput = w3.MustNewFunc(`exactInput( + ( + bytes path, + address recipient, + uint256 deadline, + uint256 amountIn, + uint256 amountOutMinimum + ) params + )`, "uint256 amountOut") + ) + + type ExactInputParams struct { + Path []byte + Recipient common.Address + Deadline *big.Int + AmountIn *big.Int + AmountOutMinimum *big.Int + } + + encodePath := func(tokenA common.Address, fee uint32, tokenB common.Address) []byte { + feeBytes := []byte{byte(fee >> 16), byte(fee >> 8), byte(fee)} + return slices.Concat(tokenA[:], feeBytes, tokenB[:]) + } + + client, err := w3.Dial("https://rpc.ankr.com/eth") + if err != nil { + // handle error + } + defer client.Close() + + // 1. Create a VM that forks the Mainnet state from the latest block + vm, err := w3vm.New( + w3vm.WithFork(client, nil), + w3vm.WithNoBaseFee(), + w3vm.WithState(w3types.State{ + // give the EOA a fake WBNB balance and approval of the router + addrWETH: { + Storage: map[common.Hash]common.Hash{ + 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 v2 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. Print the output amount + var amountOut *big.Int + if err := receipt.DecodeReturns(&amountOut); err != nil { + // handle error + } + + fmt.Printf("amount out: %s UNI\n", w3.FromWei(amountOut, 18)) + // Output: amount out: 0.0 UNI +} + func ptr[T any](t T) *T { return &t } From 53ee615a41ff983e3bb9086fb49c91fdc7f9b149 Mon Sep 17 00:00:00 2001 From: lmittmann Date: Sun, 3 Mar 2024 22:58:59 +0100 Subject: [PATCH 09/36] updated spacing --- README.md | 53 ++++++++++++++++++++++++------------------------- w3vm/vm_test.go | 3 +-- 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 8a427f39..b17d5151 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ if err := client.Call( // handle error } ``` -[Playground ↗](#https://pkg.go.dev/github.com/lmittmann/w3#example-Client) +[Playground ↗](https://pkg.go.dev/github.com/lmittmann/w3#example-Client) > [!NOTE] > #### why send batch requests? @@ -62,47 +62,46 @@ if err := client.Call( ```go // 1. Create a VM that forks the Mainnet state from the latest block vm, err := w3vm.New( - w3vm.WithFork(client, nil), - w3vm.WithNoBaseFee(), - w3vm.WithState(w3types.State{ - // give the EOA a fake WBNB balance and approval of the router - addrWETH: { - Storage: map[common.Hash]common.Hash{ - w3vm.WETHBalanceSlot(addrEOA): common.BigToHash(w3.I("1 ether")), - w3vm.WETHAllowanceSlot(addrEOA, addrRouter): common.BigToHash(w3.I("1 ether")), - }, - }, - }), + w3vm.WithFork(client, nil), + w3vm.WithNoBaseFee(), + w3vm.WithState(w3types.State{ + // give the EOA a fake WBNB balance and approval of the router + addrWETH: { + Storage: map[common.Hash]common.Hash{ + w3vm.WETHBalanceSlot(addrEOA): common.BigToHash(w3.I("1 ether")), + w3vm.WETHAllowanceSlot(addrEOA, addrRouter): common.BigToHash(w3.I("1 ether")), + }, + }, + }), ) if err != nil { - // handle error + // handle error } // 2. Simulate a UniSwap v2 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, - }, - }, + 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 + // handle error } // 3. Print the output amount var amountOut *big.Int if err := receipt.DecodeReturns(&amountOut); err != nil { - // handle error + // handle error } ``` -[Playground ↗](#https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM) +[Playground ↗](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM) ### ABI Bindings diff --git a/w3vm/vm_test.go b/w3vm/vm_test.go index 17a3bd66..e6dafe3c 100644 --- a/w3vm/vm_test.go +++ b/w3vm/vm_test.go @@ -605,8 +605,7 @@ func ExampleVM() { Deadline: big.NewInt(time.Now().Unix()), AmountIn: w3.I("1 ether"), AmountOutMinimum: w3.Big0, - }, - }, + }}, }) if err != nil { // handle error From ee98691fcaad4cc3eb55c6f42b5ea890fbe48831 Mon Sep 17 00:00:00 2001 From: lmittmann Date: Sun, 3 Mar 2024 23:00:55 +0100 Subject: [PATCH 10/36] small fix --- README.md | 2 +- w3vm/vm_test.go | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b17d5151..b8466640 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ if err != nil { // handle error } -// 3. Print the output amount +// 3. Decode output amount var amountOut *big.Int if err := receipt.DecodeReturns(&amountOut); err != nil { // handle error diff --git a/w3vm/vm_test.go b/w3vm/vm_test.go index e6dafe3c..70eb5341 100644 --- a/w3vm/vm_test.go +++ b/w3vm/vm_test.go @@ -611,14 +611,13 @@ func ExampleVM() { // handle error } - // 3. Print the output amount + // 3. Decode output amount var amountOut *big.Int if err := receipt.DecodeReturns(&amountOut); err != nil { // handle error } fmt.Printf("amount out: %s UNI\n", w3.FromWei(amountOut, 18)) - // Output: amount out: 0.0 UNI } func ptr[T any](t T) *T { return &t } From b7f775a9535c20d88b42e2ec96bca14997b46e85 Mon Sep 17 00:00:00 2001 From: lmittmann Date: Tue, 5 Mar 2024 15:17:47 +0100 Subject: [PATCH 11/36] updated VM example --- README.md | 24 +++++++++++------------- w3vm/vm_test.go | 16 +++++++--------- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index b8466640..7b2e65f7 100644 --- a/README.md +++ b/README.md @@ -60,22 +60,20 @@ if err := client.Call( [`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. ```go -// 1. Create a VM that forks the Mainnet state from the latest block +// 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{ - // give the EOA a fake WBNB balance and approval of the router - addrWETH: { - Storage: map[common.Hash]common.Hash{ - w3vm.WETHBalanceSlot(addrEOA): common.BigToHash(w3.I("1 ether")), - w3vm.WETHAllowanceSlot(addrEOA, addrRouter): common.BigToHash(w3.I("1 ether")), - }, - }, - }), + w3vm.WithFork(client, nil), + w3vm.WithNoBaseFee(), + w3vm.WithState(w3types.State{ + addrWETH: {Storage: map[common.Hash]common.Hash{ + w3vm.WETHBalanceSlot(addrEOA): common.BigToHash(w3.I("1 ether")), + w3vm.WETHAllowanceSlot(addrEOA, addrRouter): common.BigToHash(w3.I("1 ether")), + }}, + }), ) if err != nil { - // handle error + // handle error } // 2. Simulate a UniSwap v2 swap diff --git a/w3vm/vm_test.go b/w3vm/vm_test.go index 70eb5341..ef1c95ac 100644 --- a/w3vm/vm_test.go +++ b/w3vm/vm_test.go @@ -576,25 +576,23 @@ func ExampleVM() { } defer client.Close() - // 1. Create a VM that forks the Mainnet state from the latest block + // 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{ - // give the EOA a fake WBNB balance and approval of the router - addrWETH: { - Storage: map[common.Hash]common.Hash{ - w3vm.WETHBalanceSlot(addrEOA): common.BigToHash(w3.I("1 ether")), - w3vm.WETHAllowanceSlot(addrEOA, addrRouter): common.BigToHash(w3.I("1 ether")), - }, - }, + addrWETH: {Storage: map[common.Hash]common.Hash{ + w3vm.WETHBalanceSlot(addrEOA): common.BigToHash(w3.BigEther), + w3vm.WETHAllowanceSlot(addrEOA, addrRouter): common.BigToHash(w3.BigEther), + }}, }), ) if err != nil { // handle error } - // 2. Simulate a UniSwap v2 swap + // 2. Simulate a UniSwap v3 swap receipt, err := vm.Apply(&w3types.Message{ From: addrEOA, To: &addrRouter, From eb066ee80762f185a3668d5bcb024b2fd377cf92 Mon Sep 17 00:00:00 2001 From: lmittmann Date: Tue, 5 Mar 2024 15:24:09 +0100 Subject: [PATCH 12/36] . --- w3vm/vm_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/w3vm/vm_test.go b/w3vm/vm_test.go index ef1c95ac..1ff22fa8 100644 --- a/w3vm/vm_test.go +++ b/w3vm/vm_test.go @@ -583,8 +583,8 @@ func ExampleVM() { w3vm.WithNoBaseFee(), w3vm.WithState(w3types.State{ addrWETH: {Storage: map[common.Hash]common.Hash{ - w3vm.WETHBalanceSlot(addrEOA): common.BigToHash(w3.BigEther), - w3vm.WETHAllowanceSlot(addrEOA, addrRouter): common.BigToHash(w3.BigEther), + w3vm.WETHBalanceSlot(addrEOA): common.BigToHash(w3.I("1 ether")), + w3vm.WETHAllowanceSlot(addrEOA, addrRouter): common.BigToHash(w3.I("1 ether")), }}, }), ) From 93f357d72086267cb6ae47ec4217fddd712ec6bb Mon Sep 17 00:00:00 2001 From: lmittmann Date: Wed, 6 Mar 2024 08:59:40 +0100 Subject: [PATCH 13/36] dropped g1.22 function --- w3vm/vm_test.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/w3vm/vm_test.go b/w3vm/vm_test.go index 1ff22fa8..5d80d4a9 100644 --- a/w3vm/vm_test.go +++ b/w3vm/vm_test.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "math/big" - "slices" "strconv" "strings" "testing" @@ -566,8 +565,11 @@ func ExampleVM() { } encodePath := func(tokenA common.Address, fee uint32, tokenB common.Address) []byte { - feeBytes := []byte{byte(fee >> 16), byte(fee >> 8), byte(fee)} - return slices.Concat(tokenA[:], feeBytes, tokenB[:]) + path := make([]byte, 43) + copy(path, tokenA[:]) + path[20], path[21], path[22] = byte(fee>>16), byte(fee>>8), byte(fee) + copy(path[23:], tokenB[:]) + return path } client, err := w3.Dial("https://rpc.ankr.com/eth") From 64beb27a769f40db85333da89ca8bb723c67d912 Mon Sep 17 00:00:00 2001 From: lmittmann Date: Wed, 6 Mar 2024 09:36:19 +0100 Subject: [PATCH 14/36] . --- README.md | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7b2e65f7..06bac863 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ go get github.com/lmittmann/w3 [`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)) ```go // 1. Connect to an RPC endpoint @@ -49,7 +50,6 @@ if err := client.Call( // handle error } ``` -[Playground ↗](https://pkg.go.dev/github.com/lmittmann/w3#example-Client) > [!NOTE] > #### why send batch requests? @@ -59,6 +59,8 @@ if err := client.Call( [`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 a UniSwap v3 swap ([Playground ↗](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM)) + ```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 @@ -99,13 +101,26 @@ if err := receipt.DecodeReturns(&amountOut); err != nil { // handle error } ``` -[Playground ↗](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM) ### 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-function `balanceOf` + +```go +funcBalanceOf := w3.MustNewFunc("balanceOf(address)", "uint256") +``` + +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 form the contracts output data ([`Func.DecodeReturns`](https://pkg.go.dev/github.com/lmittmann/w3#Func.DecodeReturns)). + ### Utils - + From 2fca65d331fcb488f5c5b025cbb0c62f1654ffa8 Mon Sep 17 00:00:00 2001 From: lmittmann Date: Wed, 6 Mar 2024 09:37:49 +0100 Subject: [PATCH 15/36] . --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 06bac863..df6a8eed 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ go get github.com/lmittmann/w3 [`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)) +Example: Batch Request ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client)) ```go // 1. Connect to an RPC endpoint @@ -59,7 +59,7 @@ if err := client.Call( [`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 a UniSwap v3 swap ([Playground ↗](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM)) +Example: Simulate an UniSwap v3 swap ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM)) ```go // 1. Create a VM that forks the Mainnet state from the latest block, From bf6ea13c1013e336c89741d52ade8016a0726c89 Mon Sep 17 00:00:00 2001 From: lmittmann Date: Wed, 6 Mar 2024 09:43:30 +0100 Subject: [PATCH 16/36] tabs to spaces --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index df6a8eed..3e0fa902 100644 --- a/README.md +++ b/README.md @@ -65,17 +65,17 @@ Example: Simulate an UniSwap v3 swap ([Playground](https://pkg.go.dev/github.com // 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: map[common.Hash]common.Hash{ - w3vm.WETHBalanceSlot(addrEOA): common.BigToHash(w3.I("1 ether")), - w3vm.WETHAllowanceSlot(addrEOA, addrRouter): common.BigToHash(w3.I("1 ether")), - }}, - }), + w3vm.WithFork(client, nil), + w3vm.WithNoBaseFee(), + w3vm.WithState(w3types.State{ + addrWETH: {Storage: map[common.Hash]common.Hash{ + w3vm.WETHBalanceSlot(addrEOA): common.BigToHash(w3.I("1 ether")), + w3vm.WETHAllowanceSlot(addrEOA, addrRouter): common.BigToHash(w3.I("1 ether")), + }}, + }), ) if err != nil { - // handle error + // handle error } // 2. Simulate a UniSwap v2 swap From 71e21b7cf803d48122dd99162448173fbb9de912 Mon Sep 17 00:00:00 2001 From: lmittmann Date: Mon, 25 Mar 2024 09:56:06 +0100 Subject: [PATCH 17/36] renamed and linked `NewFunc` example --- README.md | 2 +- func_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3e0fa902..a98f8d5b 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ if err := receipt.DecodeReturns(&amountOut); err != nil { 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-function `balanceOf` +Example: ABI binding for the ERC20-function `balanceOf` ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-NewFunc-BalanceOf)) ```go funcBalanceOf := w3.MustNewFunc("balanceOf(address)", "uint256") diff --git a/func_test.go b/func_test.go index 286217c4..070c9f99 100644 --- a/func_test.go +++ b/func_test.go @@ -16,7 +16,7 @@ import ( "github.com/lmittmann/w3/w3types" ) -func ExampleNewFunc() { +func ExampleNewFunc_balanceOf() { // ABI binding to the balanceOf function of an ERC20 Token. funcBalanceOf, _ := w3.NewFunc("balanceOf(address)", "uint256") From 45ecd9fcf34ba9335eafe9cfbaa9fadec2e0821e Mon Sep 17 00:00:00 2001 From: lmittmann Date: Mon, 25 Mar 2024 09:56:55 +0100 Subject: [PATCH 18/36] highlight examples --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a98f8d5b..c7399479 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ go get github.com/lmittmann/w3 [`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)) +**Example:** Batch Request ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client)) ```go // 1. Connect to an RPC endpoint @@ -59,7 +59,7 @@ if err := client.Call( [`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)) +**Example:** Simulate an UniSwap v3 swap ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM)) ```go // 1. Create a VM that forks the Mainnet state from the latest block, @@ -106,7 +106,7 @@ if err := receipt.DecodeReturns(&amountOut); err != nil { 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-function `balanceOf` ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-NewFunc-BalanceOf)) +**Example:** ABI binding for the ERC20-function `balanceOf` ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-NewFunc-BalanceOf)) ```go funcBalanceOf := w3.MustNewFunc("balanceOf(address)", "uint256") From 96b4d7404b396e4128eaa41e330346581117d4ca Mon Sep 17 00:00:00 2001 From: lmittmann Date: Mon, 25 Mar 2024 10:39:55 +0100 Subject: [PATCH 19/36] added UniswapV4Swap ABI-example --- README.md | 14 ++++++++++++-- func_test.go | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c7399479..62faa53a 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ if err := client.Call( [`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)) +**Example:** Simulate an Uniswap v3 swap ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM)) ```go // 1. Create a VM that forks the Mainnet state from the latest block, @@ -106,12 +106,22 @@ if err := receipt.DecodeReturns(&amountOut); err != nil { 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-function `balanceOf` ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-NewFunc-BalanceOf)) +**Example:** ABI binding for the ERC20 function `balanceOf` ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-NewFunc-BalanceOf)) ```go funcBalanceOf := w3.MustNewFunc("balanceOf(address)", "uint256") ``` +**Example:** ABI bindings for the Uniswap v4 function `swap` ([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)), diff --git a/func_test.go b/func_test.go index 070c9f99..4ea96526 100644 --- a/func_test.go +++ b/func_test.go @@ -48,6 +48,50 @@ func ExampleNewFunc_balanceOf() { // balanceOf returns: 49406 } +func ExampleNewFunc_uniswapV4Swap() { + // ABI bindings for the Uniswap v4 swap function. + funcSwap, _ := w3.NewFunc(`swap( + (address currency0, address currency1, uint24 fee, int24 tickSpacing, address hooks) key, + (bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96) params, + bytes hookData + )`, "int256 delta") + + // ABI bindings for the PoolKey struct. + type PoolKey struct { + Currency0 common.Address + Currency1 common.Address + Fee *big.Int + TickSpacing *big.Int + Hooks common.Address + } + + // ABI bindings for the SwapParams struct. + type SwapParams struct { + ZeroForOne bool + AmountSpecified *big.Int + SqrtPriceLimitX96 *big.Int + } + + // ABI-encode the functions args. + input, _ := funcSwap.EncodeArgs( + &PoolKey{ + Currency0: w3.A("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), + Currency1: w3.A("0x6B175474E89094C44Da98b954EedeAC495271d0F"), + Fee: big.NewInt(0), + TickSpacing: big.NewInt(0), + }, + &SwapParams{ + ZeroForOne: false, + AmountSpecified: big.NewInt(0), + SqrtPriceLimitX96: big.NewInt(0), + }, + []byte{}, + ) + fmt.Printf("swap input: 0x%x\n", input) + // Output: + // swap input: 0xf3cd914c000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000000 +} + func TestNewFunc(t *testing.T) { tests := []struct { Signature string From 8a95053e6215beeb8308ad11adf72ca79f8f61ff Mon Sep 17 00:00:00 2001 From: lmittmann Date: Mon, 25 Mar 2024 10:43:54 +0100 Subject: [PATCH 20/36] ~~s~~ --- README.md | 2 +- func_test.go | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 62faa53a..7ff294b1 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ ABI bindings in `w3` are specified for individual functions using Solidity synta funcBalanceOf := w3.MustNewFunc("balanceOf(address)", "uint256") ``` -**Example:** ABI bindings for the Uniswap v4 function `swap` ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-NewFunc-UniswapV4Swap)) +**Example:** ABI binding for the Uniswap v4 function `swap` ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-NewFunc-UniswapV4Swap)) ```go funcSwap := w3.MustNewFunc(`swap( diff --git a/func_test.go b/func_test.go index 4ea96526..2a97208b 100644 --- a/func_test.go +++ b/func_test.go @@ -49,14 +49,14 @@ func ExampleNewFunc_balanceOf() { } func ExampleNewFunc_uniswapV4Swap() { - // ABI bindings for the Uniswap v4 swap function. + // ABI binding for the Uniswap v4 swap function. funcSwap, _ := w3.NewFunc(`swap( (address currency0, address currency1, uint24 fee, int24 tickSpacing, address hooks) key, (bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96) params, bytes hookData )`, "int256 delta") - // ABI bindings for the PoolKey struct. + // ABI binding for the PoolKey struct. type PoolKey struct { Currency0 common.Address Currency1 common.Address @@ -65,7 +65,7 @@ func ExampleNewFunc_uniswapV4Swap() { Hooks common.Address } - // ABI bindings for the SwapParams struct. + // ABI binding for the SwapParams struct. type SwapParams struct { ZeroForOne bool AmountSpecified *big.Int From a07b8d4e2a66a3fb15ecd604ccb697557db19915 Mon Sep 17 00:00:00 2001 From: lmittmann Date: Sat, 30 Mar 2024 10:22:22 +0100 Subject: [PATCH 21/36] added "utils" section --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 7ff294b1..cc6c980d 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,17 @@ A [`Func`](https://pkg.go.dev/github.com/lmittmann/w3#Func) can be used to ### 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. + From 611713697ef26e9636a55002a7e7eaebe212e9af Mon Sep 17 00:00:00 2001 From: lmittmann Date: Sat, 30 Mar 2024 15:02:36 +0100 Subject: [PATCH 28/36] w3types: improved example doc --- w3types/interfaces_test.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/w3types/interfaces_test.go b/w3types/interfaces_test.go index 506450a4..398e784c 100644 --- a/w3types/interfaces_test.go +++ b/w3types/interfaces_test.go @@ -9,6 +9,7 @@ import ( "github.com/lmittmann/w3/w3types" ) +// TxBySenderAndNonceFactory requests the senders transaction hash by the nonce. func TxBySenderAndNonceFactory(sender common.Address, nonce uint64) w3types.RPCCallerFactory[common.Hash] { return &getTransactionBySenderAndNonceFactory{ sender: sender, @@ -16,6 +17,9 @@ func TxBySenderAndNonceFactory(sender common.Address, nonce uint64) w3types.RPCC } } +// getTransactionBySenderAndNonceFactory implements the w3types.RPCCaller and +// w3types.RPCCallerFactory interfaces. It stores the method parameters and +// the the reference to the return value. type getTransactionBySenderAndNonceFactory struct { // params sender common.Address @@ -25,11 +29,17 @@ type getTransactionBySenderAndNonceFactory struct { returns *common.Hash } +// Returns sets the reference to the return value. +// +// Return implements the [w3types.RPCCallerFactory] interface. 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. +// +// CreateRequest implements the [w3types.RPCCaller] interface. func (f *getTransactionBySenderAndNonceFactory) CreateRequest() (rpc.BatchElem, error) { return rpc.BatchElem{ Method: "ots_getTransactionBySenderAndNonce", @@ -38,6 +48,9 @@ func (f *getTransactionBySenderAndNonceFactory) CreateRequest() (rpc.BatchElem, }, nil } +// HandleResponse handles the response of the Otterscan getTransactionBySenderAndNonce method. +// +// HandleResponse implements the [w3types.RPCCaller] interface. func (f *getTransactionBySenderAndNonceFactory) HandleResponse(elem rpc.BatchElem) error { if err := elem.Error; err != nil { return err From 7d8188714d23df6403c842ce5dfc2d77bfcb05a9 Mon Sep 17 00:00:00 2001 From: lmittmann Date: Sat, 30 Mar 2024 15:11:48 +0100 Subject: [PATCH 29/36] w3vm: added `ExampleVM_Call` --- w3vm/vm_test.go | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/w3vm/vm_test.go b/w3vm/vm_test.go index 5d80d4a9..bd9ae55e 100644 --- a/w3vm/vm_test.go +++ b/w3vm/vm_test.go @@ -538,6 +538,8 @@ func BenchmarkTransferWETH9(b *testing.B) { }) } +func ptr[T any](t T) *T { return &t } + func ExampleVM() { var ( addrEOA = w3.A("0x000000000000000000000000000000000000c0Fe") @@ -620,4 +622,31 @@ func ExampleVM() { fmt.Printf("amount out: %s UNI\n", w3.FromWei(amountOut, 18)) } -func ptr[T any](t T) *T { return &t } +func ExampleVM_Call() { + client := w3.MustDial("https://rpc.ankr.com/eth") + defer client.Close() + + addrWETH := w3.A("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2") + addrEOA := w3.A("0x000000000000000000000000000000000000c0Fe") + + vm, err := w3vm.New( + w3vm.WithFork(client, nil), + w3vm.WithState(w3types.State{ + addrWETH: {Storage: map[common.Hash]common.Hash{ + w3vm.WETHBalanceSlot(addrEOA): common.BigToHash(w3.I("1 ether")), + }}, + }), + ) + if err != nil { + // handle error + } + + balanceOf := w3.MustNewFunc("balanceOf(address)", "uint256") + var balance *big.Int + if err := vm.CallFunc(addrWETH, balanceOf, addrEOA).Returns(&balance); err != nil { + // handle error + } + fmt.Printf("%s: Balance: %s WETH\n", addrEOA, w3.FromWei(balance, 18)) + // Output: + // 0x000000000000000000000000000000000000c0Fe: Balance: 1 WETH +} From 6261256e637a01ca5d466a53de4596fec5c2e8fd Mon Sep 17 00:00:00 2001 From: lmittmann Date: Sat, 30 Mar 2024 15:25:24 +0100 Subject: [PATCH 30/36] added client example --- client_test.go | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/client_test.go b/client_test.go index 2c95a75f..2b3b3c52 100644 --- a/client_test.go +++ b/client_test.go @@ -14,7 +14,9 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" "github.com/google/go-cmp/cmp" "github.com/lmittmann/w3" @@ -115,6 +117,42 @@ func ExampleClient_Call_nonceAndBalance() { fmt.Printf("%s: Nonce: %d, Balance: ♦%s\n", addr, nonce, w3.FromWei(&balance, 18)) } +func ExampleClient_Call_sendERC20transferTx() { + client := w3.MustDial("https://rpc.ankr.com/eth") + defer client.Close() + + var ( + weth9 = w3.A("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2") + receiver = w3.A("0x000000000000000000000000000000000000c0Fe") + eoaPrv, _ = crypto.GenerateKey() + ) + + funcTransfer := w3.MustNewFunc("transfer(address receiver, uint256 amount)", "bool") + input, err := funcTransfer.EncodeArgs(receiver, w3.I("1 ether")) + if err != nil { + fmt.Printf("Failed to encode args: %v\n", err) + return + } + + signer := types.LatestSigner(params.MainnetChainConfig) + var txHash common.Hash + if err := client.Call( + eth.SendTx(types.MustSignNewTx(eoaPrv, signer, &types.DynamicFeeTx{ + Nonce: 0, + To: &weth9, + Data: input, + GasTipCap: w3.I("1 gwei"), + GasFeeCap: w3.I("100 gwei"), + Gas: 100_000, + })).Returns(&txHash), + ); err != nil { + fmt.Printf("Failed to send tx: %v\n", err) + return + } + + fmt.Printf("Sent tx: %s\n", txHash) +} + func TestClientCall(t *testing.T) { tests := []struct { Buf *bytes.Buffer From 5c262418c8bc7e849f9ae10d72c9c4c7be76ec53 Mon Sep 17 00:00:00 2001 From: lmittmann Date: Sat, 30 Mar 2024 19:28:43 +0100 Subject: [PATCH 31/36] use non breaking spaces in links --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c68c81f3..4ed53576 100644 --- a/README.md +++ b/README.md @@ -16,10 +16,10 @@ 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) +* 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) ## Getting Started From c216df5b18bca6aabfae7b137d34067bc2a068ae Mon Sep 17 00:00:00 2001 From: lmittmann Date: Sat, 30 Mar 2024 20:17:26 +0100 Subject: [PATCH 32/36] small fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4ed53576..102b9afb 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ if err != nil { // handle error } -// 2. Simulate a UniSwap v2 swap +// 2. Simulate a Uniswap v3 swap receipt, err := vm.Apply(&w3types.Message{ From: addrEOA, To: &addrRouter, From b832ffe2036843370a642ccff2a0cb247dc21c8d Mon Sep 17 00:00:00 2001 From: lmittmann Date: Sat, 30 Mar 2024 20:22:12 +0100 Subject: [PATCH 33/36] `map[common.Hash]common.Hash` -> `w3types.Storage` --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 102b9afb..fc688643 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ vm, err := w3vm.New( w3vm.WithFork(client, nil), w3vm.WithNoBaseFee(), w3vm.WithState(w3types.State{ - addrWETH: {Storage: map[common.Hash]common.Hash{ + addrWETH: {Storage: w3types.Storage{ w3vm.WETHBalanceSlot(addrEOA): common.BigToHash(w3.I("1 ether")), w3vm.WETHAllowanceSlot(addrEOA, addrRouter): common.BigToHash(w3.I("1 ether")), }}, From aec9bd33400a4e4494612c69362ad7b8ec27cede Mon Sep 17 00:00:00 2001 From: lmittmann Date: Sun, 31 Mar 2024 12:42:54 +0200 Subject: [PATCH 34/36] docs update --- docs/next.config.js | 5 +- docs/package.json | 14 +- docs/pages/_meta.js | 22 +++ docs/pages/_meta.json | 18 --- docs/pages/abi.mdx | 80 ----------- docs/pages/index.mdx | 295 +++++++++++++++++++++------------------- docs/pages/rpc.mdx | 8 -- docs/pages/style.css | 2 +- docs/pages/vm.mdx | 8 -- docs/public/favicon.ico | Bin 0 -> 33310 bytes docs/theme.config.jsx | 32 +++-- 11 files changed, 209 insertions(+), 275 deletions(-) create mode 100644 docs/pages/_meta.js delete mode 100644 docs/pages/_meta.json delete mode 100644 docs/pages/abi.mdx delete mode 100644 docs/pages/rpc.mdx delete mode 100644 docs/pages/vm.mdx create mode 100644 docs/public/favicon.ico diff --git a/docs/next.config.js b/docs/next.config.js index e6bfeef8..5817c7f9 100644 --- a/docs/next.config.js +++ b/docs/next.config.js @@ -4,13 +4,14 @@ const withNextra = nextra({ theme: 'nextra-theme-docs', themeConfig: './theme.config.jsx', staticImage: true, - flexsearch: { - codeblocks: false + search: { + codeblocks: true }, defaultShowCopyCode: true }) export default withNextra({ + output: 'export', reactStrictMode: true, images: { unoptimized: true, diff --git a/docs/package.json b/docs/package.json index ea1bc572..9f1c73d7 100644 --- a/docs/package.json +++ b/docs/package.json @@ -2,18 +2,18 @@ "type": "module", "scripts": { "dev": "next dev", - "build": "next build && next export" + "build": "next build" }, "dependencies": { - "next": "^13.4.19", - "nextra": "^2.12.3", - "nextra-theme-docs": "^2.12.3", + "next": "^14.1.4", + "nextra": "3.0.0-alpha.22", + "nextra-theme-docs": "3.0.0-alpha.22", "react": "^18.2.0", "react-dom": "^18.2.0" }, "devDependencies": { - "autoprefixer": "^10.4.15", - "postcss": "^8.4.29", - "tailwindcss": "^3.3.3" + "autoprefixer": "^10.4.19", + "postcss": "^8.4.34", + "tailwindcss": "^3.4.3" } } diff --git a/docs/pages/_meta.js b/docs/pages/_meta.js new file mode 100644 index 00000000..757dd35e --- /dev/null +++ b/docs/pages/_meta.js @@ -0,0 +1,22 @@ +export default { + index: { + title: 'Introduction', + theme: { + sidebar: false, + toc: true, + breadcrumb: false, + }, + }, + examples: { + title: 'Examples ↗', + type: 'page', + href: '/examples', + newWindow: true + }, + godoc: { + title: 'GoDoc ↗', + type: 'page', + href: 'https://pkg.go.dev/github.com/lmittmann/w3#section-documentation', + newWindow: true + }, +} diff --git a/docs/pages/_meta.json b/docs/pages/_meta.json deleted file mode 100644 index a76b6231..00000000 --- a/docs/pages/_meta.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "examples": { - "title": "Examples ↗", - "type": "page", - "href": "/examples", - "newWindow": true - }, - "godoc": { - "title": "GoDoc ↗", - "type": "page", - "href": "https://pkg.go.dev/github.com/lmittmann/w3#section-documentation", - "newWindow": true - }, - "index": { - "type": "page", - "display": "hidden" - } -} diff --git a/docs/pages/abi.mdx b/docs/pages/abi.mdx deleted file mode 100644 index b8099cae..00000000 --- a/docs/pages/abi.mdx +++ /dev/null @@ -1,80 +0,0 @@ ---- -title: ABI Bindings -draft: true ---- - -# ABI - -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. - -### Examples - -#### ERC20 `transfer` - -The ERC20 `transfer` function can be defined as follows: -```go -funcTransfer := w3.MustNewFunc("transfer(address,uint256)", "bool") -``` - -Alternatively the function arguments and returns can also be named. Note, that Solidity type aliases -are also supported (e.g. `uint` for `uint256`): -```go -funcTransfer := w3.MustNewFunc("transfer(address to, uint amount)", "bool success") -``` - -#### Tuples - -The UniSwap V3 [`IQuoterV2.sol`](https://github.com/Uniswap/v3-periphery/blob/main/contracts/interfaces/IQuoterV2.sol#L27-L53) -uses a tuple as argument for e.g. `quoteExactInputSingle`, which can be defined as follows: - -```go -funcQuoteExactInputSingle := w3.MustNewFunc( - `quoteExactInputSingle(( - address tokenIn, - address tokenOut, - uint256 amountIn, - uint24 fee, - uint160 sqrtPriceLimitX96 - ) params)`, - `uint256 amountOut, - uint160 sqrtPriceX96After, - uint32 initializedTicksCrossed, - uint256 gasEstimate`, -) -``` - -Note, that the Solidity struct arguments are wrapped in parenthesis and names are mandatory. - -### `EncodeArgs` - -### `DecodeArgs` and `DecodeReturns` - - - - -## Events - -Event ABI bindings can be defined using -* `func NewEvent(signature string) (*Event, error)`, or -* `func MustNewEvent(signature string) *Event` which panics on error. - -### Examples - -#### ERC20 `Transfer` - -```go -evtTransfer := w3.MustNewEvent("Transfer(address indexed from, address indexed to, uint256 value)") -``` diff --git a/docs/pages/index.mdx b/docs/pages/index.mdx index a9b6708d..f6125aa9 100644 --- a/docs/pages/index.mdx +++ b/docs/pages/index.mdx @@ -1,12 +1,11 @@ --- -title: Introduction -theme: - breadcrumb: false +description: 'w3: Enhanced Ethereum Integration for Go' --- import Image from 'next/image' +import { Callout } from 'nextra/components' -# w3 +# `w3`: Enhanced Ethereum Integration for Go
@@ -25,197 +24,167 @@ import Image from 'next/image' Hello -Package `w3` implements a blazing fast and modular Ethereum JSON RPC client with -first-class ABI support. +`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**. -* **Batch request** support significantly reduces the duration of requests to - both remote and local endpoints. -* **ABI** bindings are specified for individual functions using Solidity syntax. - No need for `abigen` and ABI JSON files. -* **Modular** API allows to create custom RPC method integrations that can be - used alongside the methods implemented by the package. - -`w3` is closely linked to [go-ethereum](https://github.com/ethereum/go-ethereum) -and uses a variety of its types, such as [`common.Address`](https://pkg.go.dev/github.com/ethereum/go-ethereum/common#Address) -or [`types.Transaction`](https://pkg.go.dev/github.com/ethereum/go-ethereum/core/types#Transaction). - -Batch requests with `w3` are up to **85x faster** than sequential requests with -`go-ethereum/ethclient`. - -
-Benchmarks -
-name               ethclient time/op  w3 time/op  delta
-Call_BalanceNonce  78.3ms ± 2%        39.0ms ± 1%  -50.15%  (p=0.000 n=23+22)
-Call_Balance100     3.90s ± 5%         0.05s ± 2%  -98.84%  (p=0.000 n=20+24)
-Call_BalanceOf100   3.99s ± 3%         0.05s ± 2%  -98.73%  (p=0.000 n=22+23)
-Call_Block100       6.89s ± 7%         1.94s ±11%  -71.77%  (p=0.000 n=24+23)
-
-
- -## Install ``` go get github.com/lmittmann/w3 ``` -## Getting Started +## At a Glance -> **Note** -> Check out the [examples](examples/)! +* 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) -Connect to an RPC endpoint via HTTP, WebSocket, or IPC using [`Dial`](https://pkg.go.dev/github.com/lmittmann/w3#Dial) -or [`MustDial`](https://pkg.go.dev/github.com/lmittmann/w3#MustDial). - -```go -// Connect (or panic on error) -client := w3.MustDial("https://rpc.ankr.com/eth") -defer client.Close() -``` +## Getting Started -## Batch Requests +### RPC Client -Batch request support in the [`Client`](https://pkg.go.dev/github.com/lmittmann/w3#Client) -allows to send multiple RPC requests in a single HTTP request. The speed gains -to remote endpoints are huge. Fetching 100 blocks in a single batch request -with `w3` is ~80x faster compared to sequential requests with `ethclient`. +[`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: Request the nonce and balance of an address in a single request +**Example:** Batch Request ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-Client)) ```go -var ( - addr = w3.A("0x000000000000000000000000000000000000c0Fe") +// 1. Connect to an RPC endpoint +client, err := w3.Dial("https://rpc.ankr.com/eth") +if err != nil { + // handle error +} +defer client.Close() - nonce uint64 - balance big.Int -) -err := client.Call( - eth.Nonce(addr, nil).Returns(&nonce), - eth.Balance(addr, nil).Returns(&balance), +// 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 +} ``` -## ABI Bindings + + #### 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. + -ABI bindings in `w3` are specified for individual functions using Solidity -syntax and are usable for any contract that supports that function. +#### Learn More +* List of supported [**RPC methods**](#rpc-methods) +* Learn how to create [**custom RPC method bindings**](#custom-rpc-method-bindings) -Example: ABI binding for the ERC20-function `balanceOf` +### VM -```go -funcBalanceOf := w3.MustNewFunc("balanceOf(address)", "uint256") -``` +[`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. -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 form the contracts output data ([`Func.DecodeReturns`](https://pkg.go.dev/github.com/lmittmann/w3#Func.DecodeReturns)). - -### Reading Contracts - -[`Func`](https://pkg.go.dev/github.com/lmittmann/w3#Func)'s can be used with -[`eth.CallFunc`](https://pkg.go.dev/github.com/lmittmann/w3/module/eth#CallFunc) -in the client to read contract data. +**Example:** Simulate an Uniswap v3 swap ([Playground](https://pkg.go.dev/github.com/lmittmann/w3/w3vm#example-VM)) ```go -var ( - weth9 = w3.A("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2") - dai = w3.A("0x6B175474E89094C44Da98b954EedeAC495271d0F") - - weth9Balance big.Int - daiBalance big.Int -) - -err := client.Call( - eth.CallFunc(funcBalanceOf, weth9, addr).Returns(&weth9Balance), - eth.CallFunc(funcBalanceOf, dai, addr).Returns(&daiBalance), +// 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 +} ``` -### Writing Contracts +### ABI Bindings -Sending a transaction to a contract requires three steps. +ABI bindings in `w3` are specified for individual functions using Solidity syntax and are usable for any contract that supports that function. -1. Encode the transaction input data using [`Func.EncodeArgs`](https://pkg.go.dev/github.com/lmittmann/w3#Func.EncodeArgs). +**Example:** ABI binding for the ERC20 `balanceOf` function ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-NewFunc-BalanceOf)) ```go -var funcTransfer = w3.MustNewFunc("transfer(address,uint256)", "bool") - -input, err := funcTransfer.EncodeArgs(w3.A("0x…"), w3.I("1 ether")) -``` - -2. Create a signed transaction to the contract using [go-ethereum/core/types](https://pkg.go.dev/github.com/ethereum/go-ethereum/core/types). - -```go -signer := types.LatestSigner(params.MainnetChainConfig) -tx := types.MustSignNewTx(privKey, signer, &types.DynamicFeeTx{ - To: w3.A("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), - Nonce: 0, - Data: input, - Gas: 75000, - GasFeeCap: w3.I("100 gwei"), - GasTipCap: w3.I("1 gwei"), -}) +funcBalanceOf := w3.MustNewFunc("balanceOf(address)", "uint256") ``` -3. Send the signed transaction. +**Example:** ABI binding for the Uniswap v4 `swap` function ([Playground](https://pkg.go.dev/github.com/lmittmann/w3#example-NewFunc-UniswapV4Swap)) ```go -var txHash common.Hash -err := client.Call( - eth.SendTx(tx).Returns(&txHash), -) +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 -## Custom RPC Methods - -Custom RPC methods can be called with the `w3` client by creating a -[`core.Caller`](https://pkg.go.dev/github.com/lmittmann/w3/core#Caller) -implementation. -The `w3/module/eth` package can be used as implementation reference. - +* 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 form the contracts output data ([`Func.DecodeReturns`](https://pkg.go.dev/github.com/lmittmann/w3#Func.DecodeReturns)). -## Utils +### Utils -Static addresses, hashes, hex byte slices or `big.Int`'s can be parsed from -strings with the following utility functions. +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 -var ( - addr = w3.A("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045") - hash = w3.H("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3") - bytes = w3.B("0x27c5342c") - big = w3.I("12.34 ether") -) +addr := w3.A("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045") +hash := w3.H("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3") +bytes := w3.B("0x27c5342c") +amount := w3.I("12.34 ether") ``` -Note that these functions panic if the string cannot be parsed. Use -[go-ethereum/common](https://pkg.go.dev/github.com/ethereum/go-ethereum/common) -to parse strings that may not be valid instead. +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. +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)`
`eth.CallFunc(fn core.Func, contract common.Address, args ...any).Returns(returns ...any)` +| `eth_call` | `eth.Call(msg *w3types.Message, blockNumber *big.Int, overrides w3types.State).Returns(output *[]byte)`
`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)`
`eth.HeaderByHash(hash common.Hash).Returns(header *types.Header)` -| `eth_getBlockByNumber` | `eth.BlockByNumber(number *big.Int).Returns(block *types.Block)`
`eth.HeaderByNumber(number *big.Int).Returns(header *types.Header)` +| `eth_getBlockByHash` | `eth.BlockByHash(hash common.Hash).Returns(block *types.Block)`
`eth.HeaderByHash(hash common.Hash).Returns(header *types.Header)` +| `eth_getBlockByNumber` | `eth.BlockByNumber(number *big.Int).Returns(block *types.Block)`
`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)` @@ -226,7 +195,7 @@ List of supported RPC methods. | `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)`
`eth.SendTx(tx *types.Transaction).Returns(hash *common.Hash)` +| `eth_sendRawTransaction` | `eth.SendRawTx(rawTx []byte).Returns(hash *common.Hash)`
`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)` @@ -236,8 +205,8 @@ List of supported RPC methods. | Method | Go Code | :----------------------- | :------- -| `debug_traceCall` | `debug.TraceCall(msg *w3types.Message, blockNumber *big.Int, config *debug.TraceConfig).Returns(trace *debug.Trace)`
`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)`
`debug.CallTraceTx(txHash common.Hash, overrides w3types.State).Returns(trace *debug.CallTrace)` +| `debug_traceCall` | `debug.TraceCall(msg *w3types.Message, blockNumber *big.Int, config *debug.TraceConfig).Returns(trace *debug.Trace)`
`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)`
`debug.CallTraceTx(txHash common.Hash, overrides w3types.State).Returns(trace *debug.CallTrace)` ### [`txpool`](https://pkg.go.dev/github.com/lmittmann/w3/module/txpool) @@ -258,3 +227,55 @@ List of supported RPC methods. | 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 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 +} +``` diff --git a/docs/pages/rpc.mdx b/docs/pages/rpc.mdx deleted file mode 100644 index 52fd2d25..00000000 --- a/docs/pages/rpc.mdx +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: RPC -draft: true ---- - -# RPC - -Coming soon... diff --git a/docs/pages/style.css b/docs/pages/style.css index 9230c537..0ef07e76 100644 --- a/docs/pages/style.css +++ b/docs/pages/style.css @@ -4,7 +4,7 @@ @layer base { main { - @apply dark:text-neutral-400; + @apply dark:text-neutral-300; } main strong, diff --git a/docs/pages/vm.mdx b/docs/pages/vm.mdx deleted file mode 100644 index 005d22b6..00000000 --- a/docs/pages/vm.mdx +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: VM -draft: true ---- - -# VM - -Coming soon... diff --git a/docs/public/favicon.ico b/docs/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..4f23aa8f3f18d09bcd15afa695c264f879a9803b GIT binary patch literal 33310 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
pb%EC=h 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 A^#A|> literal 0 HcmV?d00001 diff --git a/docs/theme.config.jsx b/docs/theme.config.jsx index 8c990048..7e717517 100644 --- a/docs/theme.config.jsx +++ b/docs/theme.config.jsx @@ -1,5 +1,5 @@ -import { useRouter } from 'next/router' import Image from 'next/image' +import { useConfig } from 'nextra-theme-docs' export default { logo: <> @@ -8,12 +8,19 @@ export default {
w3 , - banner: { - text: '🚧 This site is currently under construction 🚧' - }, - useNextSeoProps() { - const { pathname } = useRouter() - return { titleTemplate: pathname === '/' ? 'w3' : '%s – w3' } + head: () => { + const { frontMatter } = useConfig() + const title = frontMatter.title ? `${frontMatter.title} – w3` : 'w3' + return ( + <> + {title} + + + + ) }, footer: { component: null, @@ -21,15 +28,12 @@ export default { project: { link: 'https://github.com/lmittmann/w3', }, - editLink: { - text: 'Edit this page on GitHub' - }, feedback: { content: null, }, docsRepositoryBase: 'https://github.com/lmittmann/w3/blob/main/docs/pages', - primaryHue: { - dark: 189, - light: 191 - } + color: { + hue: 189, + saturation: 100, + }, } From 3961cb0ce570ae57520258cad22a74389fffcebf Mon Sep 17 00:00:00 2001 From: lmittmann Date: Sun, 31 Mar 2024 12:52:01 +0200 Subject: [PATCH 35/36] small css update --- docs/pages/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/index.mdx b/docs/pages/index.mdx index f6125aa9..b7c4b25e 100644 --- a/docs/pages/index.mdx +++ b/docs/pages/index.mdx @@ -22,7 +22,7 @@ import { Callout } from 'nextra/components' -Hello +Hello `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**. From ca63b9203b143bf90b99166b2d3f2a6fa6e5234f Mon Sep 17 00:00:00 2001 From: lmittmann Date: Sun, 31 Mar 2024 14:52:27 +0200 Subject: [PATCH 36/36] dep update --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 9f1c73d7..ef06d9a7 100644 --- a/docs/package.json +++ b/docs/package.json @@ -13,7 +13,7 @@ }, "devDependencies": { "autoprefixer": "^10.4.19", - "postcss": "^8.4.34", + "postcss": "^8.4.38", "tailwindcss": "^3.4.3" } }