Skip to content

Commit ce7b81f

Browse files
authored
Merge pull request #2297 from Giveth/staging
Add debug logs for the pending donations
2 parents f305a69 + 2a1efa7 commit ce7b81f

1 file changed

Lines changed: 101 additions & 12 deletions

File tree

src/services/chains/evm/transactionService.ts

Lines changed: 101 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -155,13 +155,14 @@ export async function getEvmTransactionInfoFromNetwork(
155155
},
156156
);
157157
} catch (e) {
158-
// If `getCode` fails, fall back to legacy behavior for safety
158+
// If `getCode` fails, we can't reliably determine if it's a contract.
159+
// For safety with AA wallets, skip nonce checks if we also have a high nonce or detected AA tx.
159160
logger.warn('getTransactionInfoFromNetwork() getCode failed', {
160161
error: e?.message,
161162
fromAddress: input.fromAddress,
162163
networkId,
163164
});
164-
shouldUseNonceChecks = typeof nonce === 'number';
165+
// Keep shouldUseNonceChecks as is, will be overridden by high nonce check if needed
165166
txTrace(
166167
input,
167168
'getEvmTransactionInfoFromNetwork:nonceChecks:getCode_failed',
@@ -175,16 +176,18 @@ export async function getEvmTransactionInfoFromNetwork(
175176

176177
// If nonce is suspiciously high (> 100000), it's likely an AA wallet's internal nonce
177178
// rather than an EOA nonce. Skip the check to avoid false negatives.
179+
// This check MUST happen after getCode() attempt to override any previous setting.
178180
const isSuspiciouslyHighNonce = nonce && nonce > 100000;
179181

180182
if (isSuspiciouslyHighNonce) {
181183
logger.info(
182-
'Detected suspiciously high nonce (likely AA wallet), skipping nonce validation',
184+
'Detected suspiciously high nonce (likely AA wallet), forcing nonce validation skip',
183185
{
184186
nonce,
185187
txHash: input.txHash,
186188
fromAddress: input.fromAddress,
187189
networkId,
190+
previousShouldUseNonceChecks: shouldUseNonceChecks,
188191
},
189192
);
190193
txTrace(input, 'getEvmTransactionInfoFromNetwork:high_nonce_skip', {
@@ -491,30 +494,68 @@ function extractErc20TransferFromReceipt(params: {
491494
const expectedToLower = expectedTo.toLowerCase();
492495
const expectedFromLower = expectedFrom?.toLowerCase();
493496

494-
const candidates: Array<{ from: string; to: string; amount: number }> = [];
497+
logger.debug('extractErc20TransferFromReceipt: starting search', {
498+
tokenAddress: tokenLower,
499+
expectedTo: expectedToLower,
500+
expectedFrom: expectedFromLower,
501+
expectedAmount,
502+
totalLogsCount: logs.length,
503+
});
504+
505+
// First pass: collect all Transfer events for this token to see what we have
506+
const allTokenTransfers: Array<{ from: string; to: string; amount: number }> =
507+
[];
495508
for (const log of logs) {
496509
if (!log?.topics || log.topics.length < 3) continue;
497510
if ((log.address || '').toLowerCase() !== tokenLower) continue;
498511
if ((log.topics[0] || '').toLowerCase() !== ERC20_TRANSFER_TOPIC) continue;
499512

500513
const from = ('0x' + log.topics[1].slice(26)).toLowerCase();
501514
const to = ('0x' + log.topics[2].slice(26)).toLowerCase();
502-
if (to !== expectedToLower) continue;
503515

504516
let rawValue: string;
517+
let amount: number;
505518
try {
506-
// log.data is 32-byte uint256
507519
rawValue = ethers.BigNumber.from(log.data).toString();
520+
amount = normalizeAmount(rawValue, tokenDecimals);
508521
} catch {
509522
continue;
510523
}
511-
const amount = normalizeAmount(rawValue, tokenDecimals);
512-
candidates.push({ from, to, amount });
524+
allTokenTransfers.push({ from, to, amount });
513525
}
514526

515-
if (candidates.length === 0) return null;
527+
logger.info('extractErc20TransferFromReceipt: found token transfers', {
528+
tokenAddress: tokenLower,
529+
transfersCount: allTokenTransfers.length,
530+
transfers: allTokenTransfers.slice(0, 10), // Log first 10 to avoid huge logs
531+
});
532+
533+
// Second pass: filter for expectedTo
534+
const candidates: Array<{ from: string; to: string; amount: number }> =
535+
allTokenTransfers.filter(t => t.to === expectedToLower);
536+
537+
logger.info('extractErc20TransferFromReceipt: filtered candidates', {
538+
expectedTo: expectedToLower,
539+
candidatesCount: candidates.length,
540+
candidates,
541+
});
516542

517-
// Prefer: (1) from matches expectedFrom (if provided) AND (2) amount close to expectedAmount (if provided)
543+
if (candidates.length === 0) {
544+
logger.error(
545+
'extractErc20TransferFromReceipt: no matching transfers found',
546+
{
547+
expectedTo: expectedToLower,
548+
expectedAmount,
549+
allTransfersCount: allTokenTransfers.length,
550+
allTransfers: allTokenTransfers,
551+
},
552+
);
553+
return null;
554+
}
555+
556+
// Scoring: prioritize amount match (most important), then from match
557+
// For AA wallets, the 'from' in Transfer events is often the smart wallet, not the user EOA
558+
// So we weight amount match higher than from match
518559
const scored = candidates
519560
.map(c => {
520561
const fromMatch = expectedFromLower
@@ -524,12 +565,29 @@ function extractErc20TransferFromReceipt(params: {
524565
typeof expectedAmount === 'number'
525566
? closeTo(c.amount, expectedAmount)
526567
: false;
527-
const score = (fromMatch ? 2 : 0) + (amountMatch ? 1 : 0);
568+
// Amount match = 3 points (most important), from match = 1 point
569+
const score = (amountMatch ? 3 : 0) + (fromMatch ? 1 : 0);
528570
return { c, score };
529571
})
530572
.sort((a, b) => b.score - a.score);
531573

532-
return scored[0].c;
574+
const best = scored[0];
575+
576+
// If we have multiple candidates with same score, log a warning
577+
const topScore = best.score;
578+
const tiedCandidates = scored.filter(s => s.score === topScore);
579+
if (tiedCandidates.length > 1) {
580+
logger.warn('Multiple ERC-20 transfers with same score found', {
581+
tokenAddress,
582+
expectedTo: expectedToLower,
583+
expectedFrom: expectedFromLower,
584+
expectedAmount,
585+
candidatesCount: tiedCandidates.length,
586+
topScore,
587+
});
588+
}
589+
590+
return best.c;
533591
}
534592

535593
export async function findEvmTransactionByHash(
@@ -968,6 +1026,17 @@ async function getTransactionDetailForTokenTransfer(
9681026
// Account abstraction: the outer tx goes to the EntryPoint, but the actual ERC20 transfer happens
9691027
// inside the UserOperation. In that case we validate by inspecting ERC20 Transfer logs instead of tx.to.
9701028
if (isEntryPointTx) {
1029+
logger.info(
1030+
'Detected AA EntryPoint transaction for ERC-20 token transfer',
1031+
{
1032+
txHash,
1033+
networkId,
1034+
entryPoint: transaction.to,
1035+
token: token.symbol,
1036+
tokenAddress: token.address,
1037+
},
1038+
);
1039+
9711040
const transfer = extractErc20TransferFromReceipt({
9721041
receipt,
9731042
tokenAddress: token.address,
@@ -976,17 +1045,37 @@ async function getTransactionDetailForTokenTransfer(
9761045
expectedAmount: input.amount,
9771046
tokenDecimals: token.decimals,
9781047
});
1048+
9791049
if (!transfer) {
1050+
logger.error(
1051+
'No matching ERC-20 transfer found in AA transaction receipt',
1052+
{
1053+
txHash,
1054+
expectedTo: input.toAddress,
1055+
expectedFrom: input.fromAddress,
1056+
expectedAmount: input.amount,
1057+
tokenAddress: token.address,
1058+
logsCount: receipt.logs?.length,
1059+
},
1060+
);
9801061
throw new Error(
9811062
i18n.__(
9821063
translationErrorMessagesKeys.TRANSACTION_TO_ADDRESS_IS_DIFFERENT_FROM_SENT_TO_ADDRESS,
9831064
),
9841065
);
9851066
}
1067+
9861068
transactionFrom = transfer.from;
9871069
transactionTo = transfer.to;
9881070
const amount = transfer.amount;
9891071

1072+
logger.info('Successfully extracted ERC-20 transfer from AA transaction', {
1073+
txHash,
1074+
from: transactionFrom,
1075+
to: transactionTo,
1076+
amount,
1077+
});
1078+
9901079
if (!receipt.status) {
9911080
throw new Error(
9921081
i18n.__(

0 commit comments

Comments
 (0)