github.com/status-im/status-go@v1.1.0/services/wallet/history/transfers_watcher.go (about)

     1  package history
     2  
     3  import (
     4  	"context"
     5  	"math/big"
     6  
     7  	"github.com/ethereum/go-ethereum/common"
     8  	"github.com/ethereum/go-ethereum/event"
     9  	"github.com/ethereum/go-ethereum/log"
    10  	"github.com/status-im/status-go/services/wallet/async"
    11  	"github.com/status-im/status-go/services/wallet/transfer"
    12  	"github.com/status-im/status-go/services/wallet/walletevent"
    13  )
    14  
    15  type TransfersLoadedCb func(chainID uint64, addresses []common.Address, block *big.Int)
    16  
    17  // Watcher executes a given callback whenever an account gets added/removed
    18  type Watcher struct {
    19  	feed     *event.Feed
    20  	group    *async.Group
    21  	callback TransfersLoadedCb
    22  }
    23  
    24  func NewWatcher(feed *event.Feed, callback TransfersLoadedCb) *Watcher {
    25  	return &Watcher{
    26  		feed:     feed,
    27  		callback: callback,
    28  	}
    29  }
    30  
    31  func (w *Watcher) Start() {
    32  	if w.group != nil {
    33  		return
    34  	}
    35  
    36  	w.group = async.NewGroup(context.Background())
    37  	w.group.Add(func(ctx context.Context) error {
    38  		return watch(ctx, w.feed, w.callback)
    39  	})
    40  }
    41  
    42  func (w *Watcher) Stop() {
    43  	if w.group != nil {
    44  		w.group.Stop()
    45  		w.group.Wait()
    46  		w.group = nil
    47  	}
    48  }
    49  
    50  func onTransfersLoaded(callback TransfersLoadedCb, chainID uint64, addresses []common.Address, blockNum *big.Int) {
    51  	if callback != nil {
    52  		callback(chainID, addresses, blockNum)
    53  	}
    54  }
    55  
    56  func watch(ctx context.Context, feed *event.Feed, callback TransfersLoadedCb) error {
    57  	ch := make(chan walletevent.Event, 100)
    58  	sub := feed.Subscribe(ch)
    59  	defer sub.Unsubscribe()
    60  
    61  	for {
    62  		select {
    63  		case <-ctx.Done():
    64  			return nil
    65  		case err := <-sub.Err():
    66  			if err != nil {
    67  				log.Error("history: transfers watcher subscription failed", "error", err)
    68  			}
    69  		case ev := <-ch:
    70  			if ev.Type == transfer.EventNewTransfers {
    71  				onTransfersLoaded(callback, ev.ChainID, ev.Accounts, ev.BlockNumber)
    72  			}
    73  		}
    74  	}
    75  }