-
Notifications
You must be signed in to change notification settings - Fork 20.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
isolate V2 contract interaction API into its own package
- Loading branch information
Showing
1 changed file
with
135 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
package v2 | ||
|
||
import ( | ||
"github.com/ethereum/go-ethereum" | ||
"github.com/ethereum/go-ethereum/accounts/abi" | ||
"github.com/ethereum/go-ethereum/accounts/abi/bind" | ||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/ethereum/go-ethereum/core/types" | ||
"github.com/ethereum/go-ethereum/event" | ||
) | ||
|
||
func FilterLogs[T any](instance bind.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...) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &EventIterator[T]{unpack: unpack, logs: logs, sub: sub}, nil | ||
} | ||
|
||
func WatchLogs[T any](instance bind.ContractInstance, opts *bind.WatchOpts, eventID common.Hash, unpack func(*types.Log) (*T, error), sink chan<- *T, topics ...[]any) (event.Subscription, error) { | ||
backend := instance.Backend() | ||
c := bind.NewBoundContract(instance.Address(), abi.ABI{}, backend, backend, backend) | ||
logs, sub, err := c.WatchLogs(opts, eventID.String(), topics...) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return event.NewSubscription(func(quit <-chan struct{}) error { | ||
defer sub.Unsubscribe() | ||
for { | ||
select { | ||
case log := <-logs: | ||
// New log arrived, parse the event and forward to the user | ||
ev, err := unpack(&log) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
select { | ||
case sink <- ev: | ||
case err := <-sub.Err(): | ||
return err | ||
case <-quit: | ||
return nil | ||
} | ||
case err := <-sub.Err(): | ||
return err | ||
case <-quit: | ||
return nil | ||
} | ||
} | ||
}), nil | ||
} | ||
|
||
// EventIterator is returned from FilterLogs 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 | ||
|
||
unpack func(*types.Log) (*T, error) // Unpack function for the event | ||
|
||
logs chan types.Log // Log channel receiving the found contract events | ||
sub ethereum.Subscription // Subscription for errors, completion and termination | ||
done bool // Whether the subscription completed delivering logs | ||
fail error // Occurred error to stop iteration | ||
} | ||
|
||
// Next advances the iterator to the subsequent event, returning whether there | ||
// are any more events found. In case of a retrieval or parsing error, false is | ||
// returned and Error() can be queried for the exact failure. | ||
func (it *EventIterator[T]) Next() bool { | ||
// If the iterator failed, stop iterating | ||
if it.fail != nil { | ||
return false | ||
} | ||
// If the iterator completed, deliver directly whatever's available | ||
if it.done { | ||
select { | ||
case log := <-it.logs: | ||
res, err := it.unpack(&log) | ||
if err != nil { | ||
it.fail = err | ||
return false | ||
} | ||
it.Event = res | ||
return true | ||
|
||
default: | ||
return false | ||
} | ||
} | ||
// Iterator still in progress, wait for either a data or an error event | ||
select { | ||
case log := <-it.logs: | ||
res, err := it.unpack(&log) | ||
if err != nil { | ||
it.fail = err | ||
return false | ||
} | ||
it.Event = res | ||
return true | ||
|
||
case err := <-it.sub.Err(): | ||
it.done = true | ||
it.fail = err | ||
return it.Next() | ||
} | ||
} | ||
|
||
// Error returns any retrieval or parsing error occurred during filtering. | ||
func (it *EventIterator[T]) Error() error { | ||
return it.fail | ||
} | ||
|
||
// Close terminates the iteration process, releasing any pending underlying | ||
// resources. | ||
func (it *EventIterator[T]) Close() error { | ||
it.sub.Unsubscribe() | ||
return nil | ||
} | ||
|
||
func Transact(instance bind.ContractInstance, opts *bind.TransactOpts, input []byte) (*types.Transaction, error) { | ||
var ( | ||
addr = instance.Address() | ||
backend = instance.Backend() | ||
) | ||
c := bind.NewBoundContract(addr, abi.ABI{}, backend, backend, backend) | ||
return c.RawTransact(opts, input) | ||
} | ||
|
||
func Transfer(instance bind.ContractInstance, opts *bind.TransactOpts) (*types.Transaction, error) { | ||
backend := instance.Backend() | ||
c := bind.NewBoundContract(instance.Address(), abi.ABI{}, backend, backend, backend) | ||
return c.Transfer(opts) | ||
} |