diff --git a/accounts/abi/bind/base.go b/accounts/abi/bind/base.go index a928a46c95..a0c4dc3d08 100644 --- a/accounts/abi/bind/base.go +++ b/accounts/abi/bind/base.go @@ -153,8 +153,6 @@ func DeployContract(opts *TransactOpts, abi abi.ABI, bytecode []byte, backend Co } func DeployContractRaw(opts *TransactOpts, bytecode []byte, backend ContractBackend, packedParams []byte) (common.Address, *types.Transaction, *BoundContract, error) { - // TODO: it's weird to instantiate a bound contract (implies existence of contract) in order to deploy a contract - // that doesn't yet exist c := NewBoundContract(common.Address{}, abi.ABI{}, backend, backend, backend) tx, err := c.transact(opts, nil, append(bytecode, packedParams...)) @@ -463,6 +461,12 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i return signedTx, nil } +// FilterLogsByID filters contract logs for past blocks, returning the necessary +// channels to construct a strongly typed bound iterator on top of them. +func (c *BoundContract) FilterLogsByID(opts *FilterOpts, eventID common.Hash, query ...[]interface{}) (chan types.Log, event.Subscription, error) { + return c.filterLogs(opts, eventID, query...) +} + // FilterLogs filters contract logs for past blocks, returning the necessary // channels to construct a strongly typed bound iterator on top of them. func (c *BoundContract) FilterLogs(opts *FilterOpts, name string, query ...[]interface{}) (chan types.Log, event.Subscription, error) { diff --git a/accounts/abi/bind/v2/lib.go b/accounts/abi/bind/v2/lib.go index 9345662a1a..caa6469637 100644 --- a/accounts/abi/bind/v2/lib.go +++ b/accounts/abi/bind/v2/lib.go @@ -222,22 +222,24 @@ func LinkAndDeploy(auth *bind.TransactOpts, backend bind.ContractBackend, deploy return res, nil } -// TODO: adding docs soon (jwasinger) -func FilterLogs[T any](instance *ContractInstance, opts *bind.FilterOpts, eventID common.Hash, unpack func(*types.Log) (*T, error), topics ...[]any) (*EventIterator[T], error) { +// FilterEvents returns an iterator for filtering events that match the query +// parameters (filter range, eventID, topics). If unpack returns an error, +// the iterator value is not updated, and the iterator is stopped with the +// returned error. +func FilterEvents[T any](instance *ContractInstance, opts *bind.FilterOpts, eventID common.Hash, unpack func(*types.Log) (*T, error), topics ...[]any) (*EventIterator[T], error) { backend := instance.Backend c := bind.NewBoundContract(instance.Address, abi.ABI{}, backend, backend, backend) - logs, sub, err := c.FilterLogs(opts, eventID.String(), topics...) + logs, sub, err := c.FilterLogsByID(opts, eventID, topics...) if err != nil { return nil, err } return &EventIterator[T]{unpack: unpack, logs: logs, sub: sub}, nil } -// WatchLogs causes logs emitted with a given event id from a specified -// contract to be intercepted, unpacked, and forwarded to sink. If -// unpack returns an error, the returned subscription is closed with the -// error. -func WatchLogs(instance *ContractInstance, abi abi.ABI, opts *bind.WatchOpts, eventID common.Hash, onLog func(*types.Log) error, topics ...[]any) (event.Subscription, error) { +// WatchEvents causes events emitted from a specified contract to be forwarded to +// onLog if they match the query parameters (matching eventID and topics). If +// onLog returns an error, the returned subscription is cancelled with that error. +func WatchEvents(instance *ContractInstance, abi abi.ABI, opts *bind.WatchOpts, eventID common.Hash, onLog func(*types.Log) error, topics ...[]any) (event.Subscription, error) { backend := instance.Backend c := bind.NewBoundContract(instance.Address, abi, backend, backend, backend) logs, sub, err := c.WatchLogsForId(opts, eventID, topics...) @@ -262,7 +264,7 @@ func WatchLogs(instance *ContractInstance, abi abi.ABI, opts *bind.WatchOpts, ev }), nil } -// EventIterator is returned from FilterLogs and is used to iterate over the raw logs and unpacked data for events. +// EventIterator is returned from FilterEvents and is used to iterate over the raw logs and unpacked data for events. type EventIterator[T any] struct { event *T // event containing the contract specifics and raw log diff --git a/accounts/abi/bind/v2/lib_test.go b/accounts/abi/bind/v2/lib_test.go index 3d09ac2a21..1424727c61 100644 --- a/accounts/abi/bind/v2/lib_test.go +++ b/accounts/abi/bind/v2/lib_test.go @@ -375,7 +375,6 @@ func TestEvents(t *testing.T) { t.Fatalf("error getting contract abi: %v", err) } - // TODO: why did I introduce separate type, and not just use bound contract? boundContract := ContractInstance{ res.Addrs[events.CMetaData.Pattern], backend, @@ -387,7 +386,7 @@ func TestEvents(t *testing.T) { Start: nil, Context: context.Background(), } - sub1, err := WatchLogs(&boundContract, *abi, watchOpts, events.CBasic1EventID(), func(raw *types.Log) error { + sub1, err := WatchEvents(&boundContract, *abi, watchOpts, events.CBasic1EventID(), func(raw *types.Log) error { event := &events.CBasic1{ Id: (new(big.Int)).SetBytes(raw.Topics[0].Bytes()), Data: (new(big.Int)).SetBytes(raw.Data), @@ -395,7 +394,7 @@ func TestEvents(t *testing.T) { newCBasic1Ch <- event return nil }) - sub2, err := WatchLogs(&boundContract, *abi, watchOpts, events.CBasic2EventID(), func(raw *types.Log) error { + sub2, err := WatchEvents(&boundContract, *abi, watchOpts, events.CBasic2EventID(), func(raw *types.Log) error { event := &events.CBasic2{ Flag: false, // TODO: how to unpack different types to go types? this should be exposed via abi package. Data: (new(big.Int)).SetBytes(raw.Data), @@ -448,7 +447,7 @@ done: t.Fatalf("expected event type 2 count to be 1. got %d", e2Count) } - // now, test that we can filter those events that were just caught through the subscription + // now, test that we can filter those same logs after they were included in the chain filterOpts := &bind.FilterOpts{ Start: 0, @@ -466,12 +465,11 @@ done: Data: (new(big.Int)).SetBytes(raw.Data), }, nil } - // TODO: test that returning error from unpack prevents event from being received by sink. - it, err := FilterLogs[events.CBasic1](crtctInstance, filterOpts, events.CBasic1EventID(), unpackBasic) + it, err := FilterEvents[events.CBasic1](crtctInstance, filterOpts, events.CBasic1EventID(), unpackBasic) if err != nil { t.Fatalf("error filtering logs %v\n", err) } - it2, err := FilterLogs[events.CBasic2](crtctInstance, filterOpts, events.CBasic1EventID(), unpackBasic2) + it2, err := FilterEvents[events.CBasic2](crtctInstance, filterOpts, events.CBasic2EventID(), unpackBasic2) if err != nil { t.Fatalf("error filtering logs %v\n", err) } @@ -483,11 +481,11 @@ done: for it2.Next() { e2Count++ } - if e2Count != 1 { - t.Fatalf("bad") + if e1Count != 2 { + t.Fatalf("expected e1Count of 2 from filter call. got %d", e1Count) } - if e1Count != 1 { - t.Fatalf("bad") + if e2Count != 1 { + t.Fatalf("expected e2Count of 1 from filter call. got %d", e1Count) } } @@ -549,8 +547,8 @@ func TestEventsUnpackFailure(t *testing.T) { Start: nil, Context: context.Background(), } - sub1, err := WatchLogs(&boundContract, *abi, watchOpts, events.CBasic1EventID(), unpackBasic) - sub2, err := WatchLogs(&boundContract, *abi, watchOpts, events.CBasic2EventID(), unpackBasic2) + sub1, err := WatchEvents(&boundContract, *abi, watchOpts, events.CBasic1EventID(), unpackBasic) + sub2, err := WatchEvents(&boundContract, *abi, watchOpts, events.CBasic2EventID(), unpackBasic2) defer sub1.Unsubscribe() defer sub2.Unsubscribe()