Skip to content

Commit 6637db7

Browse files
committed
feat: replace old transfer detection algorithm with multistandardbalance and transferdetector
1 parent bb8c619 commit 6637db7

33 files changed

+674
-8794
lines changed

services/wallet/activity/service_test.go

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import (
1818
"github.com/status-im/status-go/services/wallet/thirdparty"
1919
mock_token "github.com/status-im/status-go/services/wallet/token/mock/token"
2020
tokenTypes "github.com/status-im/status-go/services/wallet/token/types"
21-
"github.com/status-im/status-go/services/wallet/transfer"
2221
"github.com/status-im/status-go/services/wallet/walletevent"
2322
"github.com/status-im/status-go/t/helpers"
2423
"github.com/status-im/status-go/transactions"
@@ -108,13 +107,6 @@ func setupTransactions(t *testing.T, state testState, txCount int, testTxs []tra
108107
allAddresses = append(allAddresses, p.From, p.To)
109108
}
110109

111-
txs, fromTrs, toTrs := transfer.GenerateTestTransfers(t, state.service.db, len(pendings), txCount)
112-
for i := range txs {
113-
transfer.InsertTestTransfer(t, state.service.db, txs[i].To, &txs[i])
114-
}
115-
116-
allAddresses = append(append(allAddresses, fromTrs...), toTrs...)
117-
118110
state.tokenMock.EXPECT().LookupTokenIdentity(gomock.Any(), gomock.Any(), gomock.Any()).Return(
119111
&tokenTypes.Token{
120112
ChainID: 5,

services/wallet/activity/session_service.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import (
1919
"github.com/status-im/status-go/services/wallet/common"
2020
"github.com/status-im/status-go/services/wallet/responses"
2121
"github.com/status-im/status-go/services/wallet/routeexecution"
22-
"github.com/status-im/status-go/services/wallet/transfer"
2322
"github.com/status-im/status-go/services/wallet/walletevent"
2423
"github.com/status-im/status-go/transactions"
2524

@@ -317,12 +316,6 @@ func (s *Service) processEvents(ctx context.Context) {
317316
Hash: payload.Hash,
318317
})
319318
debounceProcessChangesFn()
320-
case transfer.EventNewTransfers:
321-
eventCount++
322-
// No updates here, these are detected with their final state, just trigger
323-
// the detection of new entries
324-
newTxs = true
325-
debounceProcessChangesFn()
326319
case routeexecution.EventRouteExecutionTransactionSent:
327320
sentTxs, ok := event.EventParams.(*responses.RouterSentTransactions)
328321
if ok && sentTxs != nil {

services/wallet/collectibles/contract_type_db.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,28 @@ import (
1010
"github.com/status-im/status-go/sqlite"
1111
)
1212

13+
type ContractTypeDB struct {
14+
db *sql.DB
15+
}
16+
17+
func NewContractTypeDB(sqlDb *sql.DB) *ContractTypeDB {
18+
return &ContractTypeDB{
19+
db: sqlDb,
20+
}
21+
}
22+
23+
func (o *ContractTypeDB) GetContractTypes(ids []thirdparty.ContractID) (map[thirdparty.ContractID]w_common.ContractType, error) {
24+
ret := make(map[thirdparty.ContractID]w_common.ContractType)
25+
var err error
26+
for _, id := range ids {
27+
ret[id], err = readContractType(o.db, id)
28+
if err != nil {
29+
return nil, err
30+
}
31+
}
32+
return ret, nil
33+
}
34+
1335
func upsertContractType(creator sqlite.StatementCreator, id thirdparty.ContractID, contractType w_common.ContractType) error {
1436
if contractType == w_common.ContractTypeUnknown {
1537
return nil

services/wallet/collectibles/ownership/controller.go

Lines changed: 125 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,18 @@ package ownership
44

55
import (
66
"context"
7+
"slices"
78
"sync"
9+
"time"
810

911
"go.uber.org/zap"
1012

1113
"github.com/ethereum/go-ethereum/common"
12-
"github.com/ethereum/go-ethereum/event"
14+
15+
"github.com/status-im/go-wallet-sdk/pkg/balance/multistandardfetcher"
16+
"github.com/status-im/go-wallet-sdk/pkg/contracts/erc1155"
17+
"github.com/status-im/go-wallet-sdk/pkg/contracts/erc721"
18+
"github.com/status-im/go-wallet-sdk/pkg/eventlog"
1319

1420
gocommon "github.com/status-im/status-go/common"
1521
"github.com/status-im/status-go/crypto/types"
@@ -18,8 +24,9 @@ import (
1824
"github.com/status-im/status-go/rpc/network"
1925
"github.com/status-im/status-go/services/accounts/accountsevent"
2026
walletCommon "github.com/status-im/status-go/services/wallet/common"
27+
"github.com/status-im/status-go/services/wallet/multistandardbalance"
2128
"github.com/status-im/status-go/services/wallet/thirdparty"
22-
"github.com/status-im/status-go/services/wallet/transfer"
29+
"github.com/status-im/status-go/services/wallet/transferdetector"
2330
"github.com/status-im/status-go/services/wallet/walletevent"
2431
)
2532

@@ -30,8 +37,6 @@ const (
3037
type loaderPerChainID = map[walletCommon.ChainID]*PeriodicalLoader
3138
type loaderPerAddressAndChainID = map[common.Address]loaderPerChainID
3239

33-
type TransferCb func(common.Address, walletCommon.ChainID, []transfer.Transfer)
34-
3540
type AccountsProvider interface {
3641
GetWalletAddresses() ([]types.Address, error)
3742
}
@@ -41,12 +46,18 @@ type NetworksProvider interface {
4146
GetPublisher() *pubsub.Publisher
4247
}
4348

49+
type BlockChainStateProvider interface {
50+
GetEstimatedBlockTime(ctx context.Context, chainID uint64, blockNumber uint64) (time.Time, error)
51+
}
52+
4453
type Controller struct {
45-
fetcher CollectibleOwnershipFetcher
46-
storage CollectibleOwnershipStorage
47-
walletFeed *event.Feed
48-
accountsProvider AccountsProvider
49-
accountsPublisher *pubsub.Publisher
54+
fetcher CollectibleOwnershipFetcher
55+
storage CollectibleOwnershipStorage
56+
accountsProvider AccountsProvider
57+
accountsPublisher *pubsub.Publisher
58+
multistandardBalancePublisher *pubsub.Publisher
59+
transferDetectorPublisher *pubsub.Publisher
60+
blockChainStateProvider BlockChainStateProvider
5061

5162
networksProvider NetworksProvider
5263

@@ -66,24 +77,28 @@ type Controller struct {
6677

6778
func NewController(
6879
storage CollectibleOwnershipStorage,
69-
walletFeed *event.Feed,
7080
accountsProvider AccountsProvider,
7181
accountsPublisher *pubsub.Publisher,
7282
networksProvider NetworksProvider,
83+
multistandardBalancePublisher *pubsub.Publisher,
84+
transferDetectorPublisher *pubsub.Publisher,
85+
blockChainStateProvider BlockChainStateProvider,
7386
fetcher CollectibleOwnershipFetcher,
7487
collectiblesPublisher *pubsub.Publisher,
7588
logger *zap.Logger,
7689
) *Controller {
7790
return &Controller{
78-
fetcher: fetcher,
79-
storage: storage,
80-
walletFeed: walletFeed,
81-
accountsProvider: accountsProvider,
82-
accountsPublisher: accountsPublisher,
83-
networksProvider: networksProvider,
84-
periodicalLoaders: make(loaderPerAddressAndChainID),
85-
collectiblesPublisher: collectiblesPublisher,
86-
logger: logger.Named("OwnershipController"),
91+
fetcher: fetcher,
92+
storage: storage,
93+
accountsProvider: accountsProvider,
94+
accountsPublisher: accountsPublisher,
95+
networksProvider: networksProvider,
96+
multistandardBalancePublisher: multistandardBalancePublisher,
97+
transferDetectorPublisher: transferDetectorPublisher,
98+
blockChainStateProvider: blockChainStateProvider,
99+
periodicalLoaders: make(loaderPerAddressAndChainID),
100+
collectiblesPublisher: collectiblesPublisher,
101+
logger: logger.Named("OwnershipController"),
87102
}
88103
}
89104

@@ -105,11 +120,14 @@ func (c *Controller) Start() {
105120
// Setup collectibles fetch when a new account gets added
106121
c.startAccountsWatcher()
107122

108-
// Setup collectibles fetch when relevant activity is detected
109-
c.startWalletEventsWatcher()
110-
111123
// Setup collectibles fetch when active networks change
112124
c.startNetworkEventsWatcher()
125+
126+
// Start balance change watcher
127+
c.startBalanceChangeWatcher()
128+
129+
// Start transfer detection watcher
130+
c.startTransferDetectionWatcher()
113131
}
114132

115133
func (c *Controller) Stop() {
@@ -120,8 +138,6 @@ func (c *Controller) Stop() {
120138
close(c.stopCh)
121139
c.stopCh = nil
122140

123-
c.stopWalletEventsWatcher()
124-
125141
c.stopPeriodicalLoaders()
126142
}
127143

@@ -237,63 +253,118 @@ func (c *Controller) startAccountsWatcher() {
237253
}()
238254
}
239255

240-
func (c *Controller) startWalletEventsWatcher() {
241-
if c.walletEventsWatcher != nil {
242-
return
243-
}
244-
245-
if c.walletFeed == nil {
256+
func (c *Controller) startNetworkEventsWatcher() {
257+
if c.networksProvider == nil {
246258
return
247259
}
248260

249-
walletEventCb := func(event walletevent.Event) {
250-
if event.Type != transfer.EventInternalERC721TransferDetected &&
251-
event.Type != transfer.EventInternalERC1155TransferDetected {
252-
return
253-
}
254-
255-
chainID := walletCommon.ChainID(event.ChainID)
256-
for _, account := range event.Accounts {
257-
c.refetchOwnershipIfRecentTransfer(account, chainID, event.At)
261+
ch, unsub := pubsub.Subscribe[network.EventActiveNetworksChanged](c.networksProvider.GetPublisher(), 10)
262+
go func() {
263+
defer gocommon.LogOnPanic()
264+
defer unsub()
265+
for {
266+
select {
267+
case <-c.stopCh:
268+
return
269+
case _, ok := <-ch:
270+
if !ok {
271+
return
272+
}
273+
c.checkPeriodicalLoaders()
274+
}
258275
}
259-
}
260-
261-
c.walletEventsWatcher = walletevent.NewWatcher(c.walletFeed, walletEventCb)
262-
263-
c.walletEventsWatcher.Start()
276+
}()
264277
}
265278

266-
func (c *Controller) stopWalletEventsWatcher() {
267-
if c.walletEventsWatcher != nil {
268-
c.walletEventsWatcher.Stop()
269-
c.walletEventsWatcher = nil
279+
func (c *Controller) startBalanceChangeWatcher() {
280+
if c.multistandardBalancePublisher == nil {
281+
return
270282
}
283+
284+
ch, unsub := pubsub.Subscribe[multistandardbalance.EventBalanceFetchFinished](c.multistandardBalancePublisher, 10)
285+
go func() {
286+
defer gocommon.LogOnPanic()
287+
defer unsub()
288+
for {
289+
select {
290+
case <-c.stopCh:
291+
return
292+
case event, ok := <-ch:
293+
if !ok {
294+
return
295+
}
296+
switch event.ResultType {
297+
case multistandardfetcher.ResultTypeERC721, multistandardfetcher.ResultTypeERC1155:
298+
if event.BalanceChanged {
299+
c.refetchOwnershipIfRecentTx(event.Key.Account, walletCommon.ChainID(event.Key.ChainID), event.NewState.FetchedAt)
300+
}
301+
}
302+
}
303+
}
304+
}()
271305
}
272306

273-
func (c *Controller) startNetworkEventsWatcher() {
274-
if c.networksProvider == nil {
307+
func (c *Controller) startTransferDetectionWatcher() {
308+
if c.transferDetectorPublisher == nil {
275309
return
276310
}
277311

278-
ch, unsub := pubsub.Subscribe[network.EventActiveNetworksChanged](c.networksProvider.GetPublisher(), 10)
312+
ch, unsub := pubsub.Subscribe[transferdetector.EventTransferDetectionFinished](c.transferDetectorPublisher, 10)
279313
go func() {
280314
defer gocommon.LogOnPanic()
281315
defer unsub()
282316
for {
283317
select {
284318
case <-c.stopCh:
285319
return
286-
case _, ok := <-ch:
320+
case msg, ok := <-ch:
287321
if !ok {
288322
return
289323
}
290-
c.checkPeriodicalLoaders()
324+
for _, event := range msg.Events {
325+
switch event.EventKey {
326+
case eventlog.ERC721Transfer:
327+
unpackedEvent, ok := event.Unpacked.(erc721.Erc721Transfer)
328+
if !ok {
329+
c.logger.Error("failed to unpack ERC721Transfer event")
330+
continue
331+
}
332+
c.refetchOwnershipIfRelevantEvent(msg.Accounts, unpackedEvent.From, unpackedEvent.To, msg.ChainID, unpackedEvent.Raw.BlockNumber)
333+
case eventlog.ERC1155TransferSingle:
334+
unpackedEvent, ok := event.Unpacked.(erc1155.Erc1155TransferSingle)
335+
if !ok {
336+
c.logger.Error("failed to unpack ERC1155TransferSingle event")
337+
continue
338+
}
339+
c.refetchOwnershipIfRelevantEvent(msg.Accounts, unpackedEvent.From, unpackedEvent.To, msg.ChainID, unpackedEvent.Raw.BlockNumber)
340+
case eventlog.ERC1155TransferBatch:
341+
unpackedEvent, ok := event.Unpacked.(erc1155.Erc1155TransferBatch)
342+
if !ok {
343+
c.logger.Error("failed to unpack ERC1155TransferBatch event")
344+
continue
345+
}
346+
c.refetchOwnershipIfRelevantEvent(msg.Accounts, unpackedEvent.From, unpackedEvent.To, msg.ChainID, unpackedEvent.Raw.BlockNumber)
347+
}
348+
}
291349
}
292350
}
293351
}()
294352
}
295353

296-
func (c *Controller) refetchOwnershipIfRecentTransfer(account common.Address, chainID walletCommon.ChainID, latestTxTimestamp int64) {
354+
func (c *Controller) refetchOwnershipIfRelevantEvent(checkedAccounts []common.Address, eventFrom common.Address, eventTo common.Address, chainID uint64, blockNumber uint64) {
355+
for _, address := range []common.Address{eventFrom, eventTo} {
356+
if slices.Contains(checkedAccounts, address) {
357+
blockTime, err := c.blockChainStateProvider.GetEstimatedBlockTime(context.TODO(), chainID, blockNumber)
358+
if err != nil {
359+
c.logger.Error("failed to get estimated block time", zap.Error(err))
360+
continue
361+
}
362+
c.refetchOwnershipIfRecentTx(address, walletCommon.ChainID(chainID), blockTime.Unix())
363+
}
364+
}
365+
}
366+
367+
func (c *Controller) refetchOwnershipIfRecentTx(account common.Address, chainID walletCommon.ChainID, latestTxTimestamp int64) {
297368
// Check last ownership update timestamp
298369
timestamp, err := c.storage.GetOwnershipUpdateTimestamp(account, chainID)
299370

0 commit comments

Comments
 (0)