Skip to content

Commit 93f9e58

Browse files
authored
v0.6.0 (#7)
* Use pointers to pass tx and calls in RPC client, add chain ID tx modifier * Add context to key methods, add RPC key * Allow to pass contract code in constructor * Add GetUncle* methods * Add GetBlockReceipts method * Add support for web3 and net RPC methods * Add safe and finalized block tags * Add filter RPC methods * Use receiver only channels in RPC client * Do not use cache map in ChainIDProvider * Update README * Allow to set fixed chain ID in ChainIDProvider * Create response channel before writing to stream
1 parent e768965 commit 93f9e58

File tree

28 files changed

+1720
-414
lines changed

28 files changed

+1720
-414
lines changed

README.md

Lines changed: 68 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ Some of key features include:
3232
* [Decoding method return values](#decoding-method-return-values)
3333
* [Events / Logs](#events--logs)
3434
* [Decoding events](#decoding-events)
35-
* [Errors](#errors)
36-
* [Reverts](#reverts)
37-
* [Panics](#panics)
3835
* [Contract ABI](#contract-abi)
3936
* [JSON-ABI](#json-abi)
4037
* [Human-Readable ABI](#human-readable-abi)
38+
* [Errors](#errors)
39+
* [Reverts](#reverts)
40+
* [Panics](#panics)
4141
* [Signature parser syntax](#signature-parser-syntax)
4242
* [Custom types](#custom-types)
4343
* [Simple types](#simple-types)
@@ -147,7 +147,7 @@ func main() {
147147
SetInput(calldata)
148148

149149
// Call balanceOf.
150-
b, _, err := c.Call(context.Background(), *call, types.LatestBlockNumber)
150+
b, _, err := c.Call(context.Background(), call, types.LatestBlockNumber)
151151
if err != nil {
152152
panic(err)
153153
}
@@ -249,7 +249,7 @@ func main() {
249249
SetInput(calldata)
250250

251251
// Call the contract.
252-
b, _, err := c.Call(context.Background(), *call, types.LatestBlockNumber)
252+
b, _, err := c.Call(context.Background(), call, types.LatestBlockNumber)
253253
if err != nil {
254254
panic(err)
255255
}
@@ -320,10 +320,6 @@ func main() {
320320
// does not have a 'From' field set.
321321
rpc.WithDefaultAddress(key.Address()),
322322

323-
// Specify a chain ID for SendTransaction when the transaction
324-
// does not have a 'ChainID' field set.
325-
rpc.WithChainID(1),
326-
327323
// TX modifiers enable modifications to the transaction before signing
328324
// and sending to the node. While not mandatory, without them, transaction
329325
// parameters like gas limit, gas price, and nonce must be set manually.
@@ -345,6 +341,12 @@ func main() {
345341
txmodifier.NewNonceProvider(txmodifier.NonceProviderOptions{
346342
UsePendingBlock: false,
347343
}),
344+
345+
// ChainIDProvider automatically sets the chain ID for the transaction.
346+
txmodifier.NewChainIDProvider(txmodifier.ChainIDProviderOptions{
347+
Replace: false,
348+
Cache: true,
349+
}),
348350
),
349351
)
350352
if err != nil {
@@ -362,7 +364,7 @@ func main() {
362364
SetTo(types.MustAddressFromHex("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48")).
363365
SetInput(calldata)
364366

365-
txHash, _, err := c.SendTransaction(context.Background(), *tx)
367+
txHash, _, err := c.SendTransaction(context.Background(), tx)
366368
if err != nil {
367369
panic(err)
368370
}
@@ -422,7 +424,7 @@ func main() {
422424
SetTopics([]types.Hash{transfer.Topic0()})
423425

424426
// Fetch logs for WETH transfer events.
425-
logs, err := c.SubscribeLogs(ctx, *query)
427+
logs, err := c.SubscribeLogs(ctx, query)
426428
if err != nil {
427429
panic(err)
428430
}
@@ -445,15 +447,15 @@ func main() {
445447
To connect to a node, it is necessary to choose a suitable transport method. The transport is responsible for executing
446448
a low-level communication protocol with the node. The `go-eth` package offers the following transport options:
447449

448-
| Transport | Description | Subscriptions |
449-
|-----------|---------------------------------------------------------------------------------------------|-----------------|
450-
| HTTP | Connects to a node using the HTTP protocol. | No |
451-
| WebSocket | Connects to a node using the WebSocket protocol. | Yes |
452-
| IPC | Connects to a node using the IPC protocol. | Yes |
453-
| Retry | Wraps a transport and retries requests in case of an error. | Yes<sup>2</sup> |
454-
| Combined | Wraps two transports and uses one for requests and the other for subscriptions.<sup>1</sup> | Yes |
450+
| Transport | Description | Subscriptions |
451+
|-----------|--------------------------------------------------------------------------------------------|-----------------|
452+
| HTTP | Connects to a node using the HTTP protocol. | No |
453+
| WebSocket | Connects to a node using the WebSocket protocol. | Yes |
454+
| IPC | Connects to a node using the IPC protocol. | Yes |
455+
| Retry | Wraps a transport and retries requests in case of an error. | Yes<sup>2</sup> |
456+
| Combined | Wraps two transports and uses one for methods and the other for subscriptions.<sup>1</sup> | Yes |
455457

456-
1. It is recommended by some RPC providers to use HTTP for requests and WebSocket for subscriptions.
458+
1. It is recommended by some RPC providers to use HTTP for methods and WebSocket for subscriptions.
457459
2. Only if the underlying transport supports subscriptions.
458460

459461
Transports can be created using the `transport.New*` functions. It is also possible to create custom transport by
@@ -470,6 +472,7 @@ The `go-eth` package provides support for the following wallet types:
470472
| JSON key file<sup>1</sup> | `key, err := wallet.NewKeyFromJSON(path, password)` |
471473
| JSON key content<sup>1</sup> | `key, err := wallet.NewKeyFromJSONContent(jsonContent, password)` |
472474
| Mnemonic | `key, err := wallet.NewKeyFromMnemonic(mnemonic, password, account, index)` |
475+
| Remote RPC | `key := wallet.NewKeyRPC(client, address)` |
473476

474477
1. Only V3 JSON keys are supported.
475478

@@ -562,8 +565,7 @@ func main() {
562565

563566
In the example above, data is encoded and decoded using a struct. The `abi` tags map the struct fields to the
564567
corresponding tuple or struct fields. These tags are optional. If absent, fields are mapped by name, with the first
565-
consecutive uppercase letters converted to lowercase. For instance, the `Number` struct field maps to the `number`
566-
field, and the `DAPPName` field maps to the `dappName` field.
568+
consecutive uppercase letters converted to lowercase.
567569

568570
It is also possible to encode and decode values to a separate variables:
569571

@@ -602,8 +604,8 @@ func main() {
602604
}
603605
```
604606

605-
Note that in both examples above, similarly named functions are used to encode and decode data. The only difference is
606-
that the second example uses the plural form of the function. The plural form is used to encode and decode data from
607+
**Note that in both examples above, similarly named functions are used to encode and decode data. The only difference is
608+
that the second example uses the plural form of the function.** The plural form is used to encode and decode data from
607609
separate variables, while the singular form is used for structs or maps. This is a common pattern in the `go-eth`
608610
package.
609611

@@ -680,8 +682,8 @@ When mapping between Go and Solidity types, the following rules apply:
680682
* ✓ - Supported
681683
* ✗ - Not supported
682684

683-
1. Destination type must be able to hold the value of the source type. For example, `uint16` can be mapped to `uint8`,
684-
but only if the value is less than 256.
685+
1. Destination type must be able to hold the value of the source type. Otherwise, the mapping will result in an error.
686+
For example, `uint16` can be mapped to `uint8`, but only if the value is less than 256.
685687
2. Mapping of negative values is supported only if both types support negative values.
686688
3. Only mapping from/to `bytes32` is supported.
687689
4. Only mapping from/to `bytes20` is supported.
@@ -783,8 +785,7 @@ func main() {
783785
To decode contract events, the `abi.Event` structure needs to be created. Events may be created using different methods:
784786

785787
- `abi.ParseEvent` / `abi.MustParseEvent` - creates a new event by parsing an event signature.
786-
-
787-
- `abi.NewEvent(name, inputs)` - creates a new event using provided arguments.
788+
- `abi.NewEvent(name, inputs)` - creates a new event using provided arguments.
788789
- Using the `abi.Contract` struct (see [Contract ABI](#contract-abi) section).
789790

790791
#### Decoding events
@@ -828,7 +829,7 @@ func main() {
828829
SetTopics([]types.Hash{transfer.Topic0()})
829830

830831
// Fetch logs for WETH transfer events.
831-
logs, err := c.GetLogs(context.Background(), *query)
832+
logs, err := c.GetLogs(context.Background(), query)
832833
if err != nil {
833834
panic(err)
834835
}
@@ -843,41 +844,18 @@ func main() {
843844
}
844845
```
845846

846-
### Errors
847-
848-
To decode custom contract errors, first a `abi.Error` struct must be created. Errors may be created using different
849-
methods:
850-
851-
- `abi.ParseError` / `abi.MustParseError` - creates a new error by parsing an error signature.
852-
- `abi.NewError(name, inputs)` - creates a new error using provided arguments.
853-
- Using the `abi.Contract` struct (see [Contract ABI](#contract-abi) section).
854-
855-
Custom errors may be decoded from errors returned by the `Call` function using the `abi.Error.HandleError` method.
856-
857-
When using a `abi.Contract`, errors may be decoded from call errors using the `abi.Contract.HandleError` method. This
858-
method will try to decode the error using all errors defined in the contract, also including reverts and panics.
859-
860-
### Reverts
861-
862-
Reverts are special errors returned by the EVM when a contract call fails. Reverts are ABI-encoded errors with
863-
the `Error(string)` signature. The `abi.DecodeRevert` function can be used to decode reverts. Optionally, the `abi`
864-
package provides `abi.Revert`, a predefined error type that can be used to decode reverts.
865-
866-
To verify if an error is a revert, use the `abi.IsRevert` function.
867-
868-
### Panics
869-
870-
Similar to reverts, panics are special errors returned by the EVM when a contract call fails. Panics are ABI-encoded
871-
errors with the `Panic(uint256)` signature. The `abi.DecodePanic` function can be used to decode panics. Optionally, the
872-
`abi` package also provides `abi.Panic`, a predefined error type that can be used to decode panics.
873-
874-
To verify if an error is a panic, use the `abi.IsPanic` function.
875-
876847
### Contract ABI
877848

878849
The `abi.Contract` structure is a utility that provides an interface to a contract. It can be created using a JSON-ABI
879850
file or by supplying a list of signatures (also known as a Human-Readable ABI).
880851

852+
To create a contract struct, the following methods may be used:
853+
854+
- `abi.LoadJSON` / `abi.MustLoadJSON` - creates a new contract by loading a JSON-ABI file.
855+
- `abi.ParseJSON` / `abi.MustParseJSON` - creates a new contract by parsing a JSON-ABI string.
856+
- `abi.ParseSignatures` / `abi.MustParseSignatures` - creates a new contract by parsing a list of signatures (
857+
Human-Readable ABI).
858+
881859
#### JSON-ABI
882860

883861
<!-- examples/contract-json-abi/main.go -->
@@ -956,6 +934,36 @@ func main() {
956934
}
957935
```
958936

937+
### Errors
938+
939+
To decode custom contract errors, first a `abi.Error` struct must be created. Errors may be created using different
940+
methods:
941+
942+
- `abi.ParseError` / `abi.MustParseError` - creates a new error by parsing an error signature.
943+
- `abi.NewError(name, inputs)` - creates a new error using provided arguments.
944+
- Using the `abi.Contract` struct (see [Contract ABI](#contract-abi) section).
945+
946+
Custom errors may be decoded from errors returned by the `Call` function using the `abi.Error.HandleError` method.
947+
948+
When using a `abi.Contract`, errors may be decoded from call errors using the `abi.Contract.HandleError` method. This
949+
method will try to decode the error using all errors defined in the contract, also including reverts and panics.
950+
951+
### Reverts
952+
953+
Reverts are special errors returned by the EVM when a contract call fails. Reverts are ABI-encoded errors with
954+
the `Error(string)` signature. The `abi.DecodeRevert` function can be used to decode reverts. Optionally, the `abi`
955+
package provides `abi.Revert`, a predefined error type that can be used to decode reverts.
956+
957+
To verify if an error is a revert, use the `abi.IsRevert` function.
958+
959+
### Panics
960+
961+
Similar to reverts, panics are special errors returned by the EVM when a contract call fails. Panics are ABI-encoded
962+
errors with the `Panic(uint256)` signature. The `abi.DecodePanic` function can be used to decode panics. Optionally, the
963+
`abi` package also provides `abi.Panic`, a predefined error type that can be used to decode panics.
964+
965+
To verify if an error is a panic, use the `abi.IsPanic` function.
966+
959967
### Signature parser syntax
960968

961969
The parser is based on Solidity grammar, but it allows for the omission of argument names, as well as the `returns`
@@ -974,7 +982,8 @@ Examples of signatures that are accepted by the parser:
974982

975983
### Custom types
976984

977-
It is possible to add custom types to the `abi` package.
985+
The `go-eth` package allows for the creation of custom types that can be used with the ABI encoder and decoder and with
986+
the signature parser.
978987

979988
#### Simple types
980989

abi/constructor.go

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -70,38 +70,46 @@ func (m *Constructor) Inputs() *TupleType {
7070
return m.inputs
7171
}
7272

73-
// EncodeArg encodes arguments for a constructor call using a provided map or
74-
// structure. The map or structure must have fields with the same names as
75-
// the constructor arguments.
76-
func (m *Constructor) EncodeArg(arg any) ([]byte, error) {
73+
// EncodeArg encodes an argument for a contract deployment.
74+
// The map or structure must have fields with the same names as the
75+
// constructor arguments.
76+
func (m *Constructor) EncodeArg(code []byte, arg any) ([]byte, error) {
7777
encoded, err := m.abi.EncodeValue(m.inputs, arg)
7878
if err != nil {
7979
return nil, err
8080
}
81-
return encoded, nil
81+
input := make([]byte, len(code)+len(encoded))
82+
copy(input, code)
83+
copy(input[len(code):], encoded)
84+
return input, nil
8285
}
8386

8487
// MustEncodeArg is like EncodeArg but panics on error.
85-
func (m *Constructor) MustEncodeArg(arg any) []byte {
86-
encoded, err := m.EncodeArg(arg)
88+
func (m *Constructor) MustEncodeArg(code []byte, arg any) []byte {
89+
encoded, err := m.EncodeArg(code, arg)
8790
if err != nil {
8891
panic(err)
8992
}
9093
return encoded
9194
}
9295

93-
// EncodeArgs encodes arguments for a constructor call.
94-
func (m *Constructor) EncodeArgs(args ...any) ([]byte, error) {
96+
// EncodeArgs encodes arguments for a contract deployment.
97+
// The map or structure must have fields with the same names as the
98+
// constructor arguments.
99+
func (m *Constructor) EncodeArgs(code []byte, args ...any) ([]byte, error) {
95100
encoded, err := m.abi.EncodeValues(m.inputs, args...)
96101
if err != nil {
97102
return nil, err
98103
}
99-
return encoded, nil
104+
input := make([]byte, len(code)+len(encoded))
105+
copy(input, code)
106+
copy(input[len(code):], encoded)
107+
return input, nil
100108
}
101109

102110
// MustEncodeArgs is like EncodeArgs but panics on error.
103-
func (m *Constructor) MustEncodeArgs(args ...any) []byte {
104-
encoded, err := m.EncodeArgs(args...)
111+
func (m *Constructor) MustEncodeArgs(code []byte, args ...any) []byte {
112+
encoded, err := m.EncodeArgs(code, args...)
105113
if err != nil {
106114
panic(err)
107115
}

abi/constructor_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,14 @@ func TestConstructor_EncodeArgs(t *testing.T) {
4444
arg []any
4545
expected string
4646
}{
47-
{signature: "constructor()", arg: nil, expected: ""},
48-
{signature: "constructor(uint256)", arg: []any{1}, expected: "0000000000000000000000000000000000000000000000000000000000000001"},
47+
{signature: "constructor()", arg: nil, expected: "aabb"},
48+
{signature: "constructor(uint256)", arg: []any{1}, expected: "aabb0000000000000000000000000000000000000000000000000000000000000001"},
4949
}
5050
for n, tt := range tests {
5151
t.Run(fmt.Sprintf("case-%d", n+1), func(t *testing.T) {
5252
c, err := ParseConstructor(tt.signature)
5353
require.NoError(t, err)
54-
enc, err := c.EncodeArgs(tt.arg...)
54+
enc, err := c.EncodeArgs([]byte{0xAA, 0xBB}, tt.arg...)
5555
require.NoError(t, err)
5656
assert.Equal(t, tt.expected, hex.EncodeToString(enc))
5757
})

examples/call-abi/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ func main() {
7878
SetInput(calldata)
7979

8080
// Call the contract.
81-
b, _, err := c.Call(context.Background(), *call, types.LatestBlockNumber)
81+
b, _, err := c.Call(context.Background(), call, types.LatestBlockNumber)
8282
if err != nil {
8383
panic(err)
8484
}

examples/call/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func main() {
3636
SetInput(calldata)
3737

3838
// Call balanceOf.
39-
b, _, err := c.Call(context.Background(), *call, types.LatestBlockNumber)
39+
b, _, err := c.Call(context.Background(), call, types.LatestBlockNumber)
4040
if err != nil {
4141
panic(err)
4242
}

examples/custom-type-advanced/main.go

Lines changed: 0 additions & 29 deletions
This file was deleted.

0 commit comments

Comments
 (0)