Skip to content

Commit 3ee14af

Browse files
curryxbocorey
andauthored
Add nonce checking (#845)
Co-authored-by: corey <[email protected]>
1 parent 71d75d9 commit 3ee14af

File tree

1 file changed

+34
-4
lines changed

1 file changed

+34
-4
lines changed

token-price-oracle/updater/tx_manager.go

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,27 +28,55 @@ func NewTxManager(l2Client *client.L2Client) *TxManager {
2828

2929
// SendTransaction sends a transaction in a thread-safe manner
3030
// It ensures only one transaction is sent at a time to avoid nonce conflicts
31+
// Before sending, it checks if there are any pending transactions by comparing nonces
3132
func (m *TxManager) SendTransaction(ctx context.Context, txFunc func(*bind.TransactOpts) (*types.Transaction, error)) (*types.Receipt, error) {
3233
m.mu.Lock()
3334
defer m.mu.Unlock()
3435

36+
fromAddr := m.l2Client.WalletAddress()
37+
38+
// Check if there are pending transactions by comparing nonces
39+
confirmedNonce, err := m.l2Client.GetClient().NonceAt(ctx, fromAddr, nil)
40+
if err != nil {
41+
return nil, fmt.Errorf("failed to get confirmed nonce: %w", err)
42+
}
43+
44+
pendingNonce, err := m.l2Client.GetClient().PendingNonceAt(ctx, fromAddr)
45+
if err != nil {
46+
return nil, fmt.Errorf("failed to get pending nonce: %w", err)
47+
}
48+
49+
if pendingNonce > confirmedNonce {
50+
// There are pending transactions, don't send new one
51+
log.Warn("Found pending transactions, skipping this round",
52+
"address", fromAddr.Hex(),
53+
"confirmed_nonce", confirmedNonce,
54+
"pending_nonce", pendingNonce,
55+
"pending_count", pendingNonce-confirmedNonce)
56+
return nil, fmt.Errorf("pending transactions exist (confirmed: %d, pending: %d)", confirmedNonce, pendingNonce)
57+
}
58+
59+
log.Info("No pending transactions, proceeding to send",
60+
"address", fromAddr.Hex(),
61+
"nonce", confirmedNonce)
62+
3563
// Get transaction options (returns a copy)
3664
auth := m.l2Client.GetOpts()
3765
auth.Context = ctx
38-
66+
3967
// First, estimate gas with GasLimit = 0
4068
auth.GasLimit = 0
4169
auth.NoSend = true
4270
tx, err := txFunc(auth)
4371
if err != nil {
4472
return nil, fmt.Errorf("failed to estimate gas: %w", err)
4573
}
46-
74+
4775
// Use 1.5x of estimated gas as the actual gas limit
4876
estimatedGas := tx.Gas()
4977
auth.GasLimit = estimatedGas * 3 / 2
5078
log.Info("Gas estimation completed", "estimated", estimatedGas, "actual_limit", auth.GasLimit)
51-
79+
5280
// Now send the actual transaction
5381
auth.NoSend = false
5482
tx, err = txFunc(auth)
@@ -58,16 +86,18 @@ func (m *TxManager) SendTransaction(ctx context.Context, txFunc func(*bind.Trans
5886

5987
log.Info("Transaction sent",
6088
"tx_hash", tx.Hash().Hex(),
89+
"nonce", tx.Nonce(),
6190
"gas_limit", tx.Gas())
6291

63-
// Wait for transaction to be mined with custom timeout and retry logic
92+
// Wait for transaction to be mined with timeout and retry logic
6493
receipt, err := m.waitForReceipt(ctx, tx.Hash(), 60*time.Second, 2*time.Second)
6594
if err != nil {
6695
log.Error("Failed to wait for transaction receipt",
6796
"tx_hash", tx.Hash().Hex(),
6897
"error", err)
6998
return nil, err
7099
}
100+
71101
return receipt, nil
72102
}
73103

0 commit comments

Comments
 (0)