Skip to content

Commit 2b72dab

Browse files
author
Ken Erwin
committed
fixed missing txes
1 parent 138187b commit 2b72dab

File tree

3 files changed

+155
-7
lines changed

3 files changed

+155
-7
lines changed

backend/internal/ingestor/etherscan.go

Lines changed: 134 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,23 @@ type EtherscanTransaction struct {
5151
Confirmations string `json:"confirmations"`
5252
}
5353

54+
type EtherscanTransferEvent struct {
55+
BlockNumber string `json:"blockNumber"`
56+
TimeStamp string `json:"timeStamp"`
57+
TransactionHash string `json:"transactionHash"`
58+
LogIndex string `json:"logIndex"`
59+
From string `json:"from"`
60+
To string `json:"to"`
61+
Value string `json:"value"`
62+
ContractAddress string `json:"address"`
63+
TransactionIndex string `json:"transactionIndex"`
64+
GasUsed string `json:"gasUsed"`
65+
CumulativeGasUsed string `json:"cumulativeGasUsed"`
66+
BlockHash string `json:"blockHash"`
67+
Data string `json:"data"`
68+
Topics []string `json:"topics"`
69+
}
70+
5471
func NewEtherscanClient(apiKey string, logger *zap.Logger) *EtherscanClient {
5572
return &EtherscanClient{
5673
apiKey: apiKey,
@@ -127,7 +144,7 @@ func (c *EtherscanClient) GetTransactions(ctx context.Context, startBlock, endBl
127144
var rawResp json.RawMessage
128145
if err := c.makeRequestWithRetry(ctx, params, &rawResp); err != nil {
129146
if strings.Contains(err.Error(), "No transactions found") {
130-
c.logger.Info("No transactions found for address",
147+
c.logger.Debug("No transactions found for address",
131148
zap.String("address", address))
132149
continue // Skip this address and continue with the next one
133150
}
@@ -181,12 +198,80 @@ func (c *EtherscanClient) GetTransactions(ctx context.Context, startBlock, endBl
181198
allTransactions = append(allTransactions, transactions...)
182199
}
183200

184-
c.logger.Info("Finished processing all addresses",
201+
// Fetch Transfer events for the NFT contracts
202+
transferEvents, err := c.GetTransferEvents(ctx, startBlock, endBlock)
203+
204+
if err != nil {
205+
c.logger.Info(err.Error())
206+
if strings.Contains(err.Error(), "No records found") {
207+
c.logger.Debug("No records found for contract")
208+
} else {
209+
c.logger.Error("Failed to fetch transfer events", zap.Error(err))
210+
}
211+
} else {
212+
c.logger.Debug("Transfer events found", zap.Int("count", len(transferEvents)))
213+
c.logger.Debug("Transfer events", zap.Any("events", transferEvents))
214+
for _, event := range transferEvents {
215+
transaction := ConvertTransferEventToTransaction(event)
216+
c.logger.Debug("Transaction", zap.Any("transaction", transaction))
217+
allTransactions = append(allTransactions, transaction)
218+
}
219+
}
220+
221+
c.logger.Debug("Finished processing all transactions",
185222
zap.Int("totalTransactions", len(allTransactions)))
186223

187224
return allTransactions, nil
188225
}
189226

227+
func (c *EtherscanClient) GetTransferEvents(ctx context.Context, startBlock, endBlock int64) ([]EtherscanTransferEvent, error) {
228+
contractAddresses := []string{
229+
"0x050dc61dFB867E0fE3Cf2948362b6c0F3fAF790b", // OpenSea contract address
230+
// Add other relevant contract addresses here
231+
}
232+
233+
var allEvents []EtherscanTransferEvent
234+
235+
for _, contract := range contractAddresses {
236+
params := map[string]string{
237+
"module": "logs",
238+
"action": "getLogs",
239+
"fromBlock": strconv.FormatInt(startBlock, 10),
240+
"toBlock": strconv.FormatInt(endBlock, 10),
241+
"address": contract,
242+
"topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", // Transfer event signature
243+
"apikey": c.apiKey,
244+
}
245+
246+
var rawResp json.RawMessage
247+
if err := c.makeRequestWithRetry(ctx, params, &rawResp); err != nil {
248+
if strings.Contains(err.Error(), "No records found") {
249+
c.logger.Debug("No records found for contract", zap.String("contract", contract))
250+
continue
251+
} else {
252+
c.logger.Error("Failed to fetch transfer events",
253+
zap.Error(err),
254+
zap.String("contract", contract))
255+
continue
256+
}
257+
}
258+
c.logger.Debug("Raw response", zap.String("rawResponse", string(rawResp)))
259+
260+
var events []EtherscanTransferEvent
261+
if err := json.Unmarshal(rawResp, &events); err != nil {
262+
c.logger.Error("Failed to unmarshal transfer events",
263+
zap.Error(err),
264+
zap.String("rawResponse", string(rawResp)),
265+
zap.String("contract", contract))
266+
continue
267+
}
268+
269+
allEvents = append(allEvents, events...)
270+
}
271+
272+
return allEvents, nil
273+
}
274+
190275
func (c *EtherscanClient) makeRequest(ctx context.Context, params map[string]string, result interface{}) error {
191276
if err := c.limiter.Wait(ctx); err != nil {
192277
return fmt.Errorf("rate limiter wait: %w", err)
@@ -258,3 +343,50 @@ func (c *EtherscanClient) makeRequestWithRetry(ctx context.Context, params map[s
258343

259344
return backoff.Retry(operation, b)
260345
}
346+
347+
// ConvertTransferEventToTransaction converts an EtherscanTransferEvent to an EtherscanTransaction
348+
func ConvertTransferEventToTransaction(event EtherscanTransferEvent) EtherscanTransaction {
349+
// event.BlockNumber is a string hex value, need to convert to int but still as string
350+
blockNumber, _ := strconv.ParseInt(event.BlockNumber[2:], 16, 64)
351+
timeStamp, _ := strconv.ParseInt(event.TimeStamp[2:], 16, 64) // Convert hex to int64
352+
nonce, _ := strconv.ParseInt(event.LogIndex[2:], 16, 64) // Convert hex to int64
353+
gas, _ := strconv.ParseInt(event.GasUsed[2:], 16, 64) // Convert hex to int64
354+
355+
// Construct the input data for safeTransferFrom
356+
from := "0x" + event.Topics[1][26:] // Extracting the 'from' address from topics
357+
to := "0x" + event.Topics[2][26:] // Extracting the 'to' address from topics
358+
tokenId := event.Topics[3] // Token ID in hex
359+
360+
// Pad addresses and tokenId to 32 bytes (64 hex characters)
361+
paddedFrom := fmt.Sprintf("%064s", strings.TrimPrefix(from, "0x"))
362+
paddedTo := fmt.Sprintf("%064s", strings.TrimPrefix(to, "0x"))
363+
paddedTokenId := fmt.Sprintf("%064s", strings.TrimPrefix(tokenId, "0x"))
364+
365+
// safeTransferFrom(address,address,uint256) method signature
366+
methodSignature := "0x42842e0e"
367+
inputData := methodSignature + paddedFrom + paddedTo + paddedTokenId
368+
369+
return EtherscanTransaction{
370+
BlockNumber: strconv.FormatInt(blockNumber, 10),
371+
TimeStamp: strconv.FormatInt(timeStamp, 10), // Convert int64 to string
372+
Hash: event.TransactionHash,
373+
From: from,
374+
To: "0x050dc61dfb867e0fe3cf2948362b6c0f3faf790b",
375+
Value: "0", // safeTransferFrom typically has no value transfer
376+
ContractAddress: event.ContractAddress,
377+
TransactionIndex: event.TransactionIndex,
378+
Gas: strconv.FormatInt(gas, 10),
379+
GasUsed: strconv.FormatInt(gas, 10),
380+
GasPrice: "0",
381+
CumulativeGasUsed: "0",
382+
Nonce: strconv.FormatInt(nonce, 10),
383+
Confirmations: "0",
384+
Input: inputData, // Set the input data to mimic safeTransferFrom
385+
}
386+
}
387+
388+
// Helper function to parse hex string to uint64
389+
func parseHexToUint64(hexStr string) uint64 {
390+
value, _ := strconv.ParseUint(hexStr[2:], 16, 64)
391+
return value
392+
}

backend/internal/ingestor/ingestor.go

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,12 @@ func (i *Ingestor) processTransaction(ctx context.Context, tx *EtherscanTransact
284284
confirmations, _ := new(big.Int).SetString(tx.Confirmations, 10)
285285

286286
transactionIndex, _ := strconv.Atoi(tx.TransactionIndex)
287-
287+
// Make sure nonce is valid
288+
if tx.Nonce == "" {
289+
i.logger.Warn("Skipping transaction with invalid nonce", zap.String("hash", tx.Hash))
290+
i.logger.Info("Transaction", zap.Any("transaction", tx))
291+
return nil
292+
}
288293
transaction := db.InsertPixelMapTransactionParams{
289294
BlockNumber: blockNumber.Int64(),
290295
TimeStamp: time.Unix(timeStamp.Int64(), 0),
@@ -317,7 +322,9 @@ func (i *Ingestor) processTransaction(ctx context.Context, tx *EtherscanTransact
317322
} else if tx.To == "0x050dc61dfb867e0fe3cf2948362b6c0f3faf790b" {
318323
abi, _ = pixelmapWrapper.PixelMapWrapperMetaData.GetAbi()
319324
} else {
325+
// It's a transfer
320326
fmt.Println("Unknown contract address", tx.To)
327+
fmt.Printf("transaction: %+v\n", tx)
321328
return nil
322329
}
323330

@@ -566,7 +573,6 @@ func (i *Ingestor) fetchTransactions(ctx context.Context, fromBlock, toBlock int
566573
}
567574

568575
if err.Error() == "API error: No transactions found" {
569-
// i.logger.Info("No transactions found in block range", zap.Int64("from", fromBlock), zap.Int64("to", toBlock))
570576
return nil, nil
571577
}
572578

@@ -593,11 +599,11 @@ func (i *Ingestor) fetchTransactions(ctx context.Context, fromBlock, toBlock int
593599
return nil, fmt.Errorf("failed to get transactions for blocks %d-%d after %d attempts: %w", fromBlock, toBlock, i.maxRetries, err)
594600
}
595601

596-
i.logger.Info("Processing transactions", zap.Int("count", len(transactions)), zap.Int64("from", fromBlock), zap.Int64("to", toBlock))
602+
i.logger.Debug("Processing transactions", zap.Int("count", len(transactions)), zap.Int64("from", fromBlock), zap.Int64("to", toBlock))
597603
return transactions, nil
598604
}
599605

600-
func (i *Ingestor) updateLastProcessedBlock(ctx context.Context, blockNumber int64) error {
606+
unc (i *Ingestor) updateLastProcessedBlock(ctx context.Context, blockNumber int64) error {
601607
if err := i.queries.UpdateLastProcessedBlock(ctx, blockNumber); err != nil {
602608
i.logger.Error("Failed to update last processed block", zap.Error(err), zap.Int64("block", blockNumber))
603609
return fmt.Errorf("failed to update last processed block: %w", err)
@@ -869,21 +875,29 @@ func (i *Ingestor) processTileUpdate(ctx context.Context, location *big.Int, ima
869875

870876
func (i *Ingestor) processTransfer(ctx context.Context, args []interface{}, tx *EtherscanTransaction, timestamp, blockNumber int64, transactionIndex int32) error {
871877
if len(args) < 3 {
878+
i.logger.Error("Insufficient arguments for transfer")
879+
os.Exit(1)
872880
return fmt.Errorf("insufficient arguments for transfer")
873881
}
874882

875883
from, ok := args[0].(common.Address)
876884
if !ok {
885+
i.logger.Error("Invalid 'from' address")
886+
os.Exit(1)
877887
return fmt.Errorf("invalid 'from' address")
878888
}
879889

880890
to, ok := args[1].(common.Address)
881891
if !ok {
892+
i.logger.Error("Invalid 'to' address")
893+
os.Exit(1)
882894
return fmt.Errorf("invalid 'to' address")
883895
}
884896

885897
location, ok := args[2].(*big.Int)
886898
if !ok {
899+
i.logger.Error("Invalid location")
900+
os.Exit(1)
887901
return fmt.Errorf("invalid location")
888902
}
889903

@@ -936,6 +950,8 @@ func (i *Ingestor) processTransfer(ctx context.Context, args []interface{}, tx *
936950
Ens: ensName,
937951
})
938952
if err != nil {
953+
i.logger.Error("Failed to update tile owner", zap.Error(err), zap.String("location", location.String()))
954+
os.Exit(1)
939955
return fmt.Errorf("failed to update tile owner: %w", err)
940956
}
941957

backend/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import (
1818
)
1919

2020
func main() {
21-
logger := prettyconsole.NewLogger(zap.DebugLevel)
21+
logger := prettyconsole.NewLogger(zap.InfoLevel)
2222
if err := godotenv.Load(); err != nil {
2323
log.Fatal("Error loading .env file")
2424
}

0 commit comments

Comments
 (0)