Skip to content

Conversation

@d4mr
Copy link
Contributor

@d4mr d4mr commented Jun 9, 2025

Introducing new experimental env vars for mine worker polling frequency configuration:

    // base value, is multiplied with number of attempts and scaling factor to get the actual value
    EXPERIMENTAL__MINE_WORKER_BASE_POLL_INTERVAL_SECONDS: z.coerce
      .number()
      .default(2),
      
    // max value, if the base * scaling_factor * number_of_attempts is greater than this, then we use this value instead
    EXPERIMENTAL__MINE_WORKER_MAX_POLL_INTERVAL_SECONDS: z.coerce
      .number()
      .default(20),
      
    // linear scaling factor
    EXPERIMENTAL__MINE_WORKER_POLL_INTERVAL_SCALING_FACTOR: z.coerce
      .number()
      .gt(0.0, "scaling factor must be greater than 0")
      .default(1.0),

Also bring AA header compatibility to /backend-wallet/transfer endpoint


PR-Codex overview

This PR introduces enhancements to the transaction mining worker by adding configurable polling intervals and improves the transaction handling logic in the transfer function, including the use of a queue for ERC20 token transfers.

Detailed summary

  • Added constants for SCALING_FACTOR, MAX_POLL_INTERVAL_MS, and BASE_POLL_INTERVAL_MS in src/worker/tasks/mine-transaction-worker.ts.
  • Updated the backoff strategy in the worker settings to use the new polling interval constants.
  • Introduced new environment variables in src/shared/utils/env.ts for configuring polling intervals.
  • Modified the transfer function in src/server/routes/backend-wallet/transfer.ts to handle both native and ERC20 token transfers.
  • Replaced direct transaction insertion with a queuing mechanism for ERC20 transfers.
  • Updated header schema references from walletHeaderSchema to walletWithAAHeaderSchema.

✨ Ask PR-Codex anything about this PR by commenting with /codex {your question}

Summary by CodeRabbit

  • New Features
    • Added support for account abstraction (AA) in transfer operations with new headers and enhanced transaction handling.
    • Introduced configurable environment variables to customize mine worker polling intervals.
  • Refactor
    • Updated mine transaction worker to use environment-driven backoff timing, replacing fixed retry intervals with configurable settings.

@coderabbitai
Copy link

coderabbitai bot commented Jun 9, 2025

Walkthrough

The changes introduce support for account abstraction (AA) in the transfer route, updating header schemas and transaction handling accordingly. Environment configuration is expanded with new variables for mine worker polling intervals. The mine transaction worker now uses these environment-driven settings for its backoff strategy, replacing hardcoded timing values.

Changes

File(s) Change Summary
src/server/routes/backend-wallet/transfer.ts Updated transfer route to support AA headers and logic, conditionally handling UserOp fields and queuing logic.
src/shared/utils/env.ts Added three environment variables for mine worker polling intervals to the schema and runtime environment.
src/worker/tasks/mine-transaction-worker.ts Replaced hardcoded backoff timing with environment-driven configuration for polling intervals.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant TransferRoute
    participant TransactionService

    Client->>TransferRoute: POST /transfer with headers (AA or non-AA)
    TransferRoute->>TransferRoute: Parse headers (walletWithAAHeaderSchema)
    alt Native token transfer
        TransferRoute->>TransactionService: insertTransaction (isUserOp, AA params if present)
        TransactionService-->>TransferRoute: queueId
    else ERC20 token transfer
        TransferRoute->>TransactionService: queueTransaction (prepared tx, AA params, overrides, etc.)
        TransactionService-->>TransferRoute: queueId
    end
    TransferRoute-->>Client: Respond with queueId
Loading
sequenceDiagram
    participant MineWorker
    participant EnvConfig

    MineWorker->>EnvConfig: Load BASE, MAX, SCALING_FACTOR poll intervals
    loop Backoff on retry
        MineWorker->>MineWorker: Calculate delay = min(attempts * BASE * SCALING_FACTOR, MAX)
        MineWorker->>MineWorker: Wait for delay before next poll
    end
Loading

📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9a0c307 and 63b48ef.

📒 Files selected for processing (1)
  • src/server/routes/backend-wallet/transfer.ts (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/server/routes/backend-wallet/transfer.ts
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (3)
src/worker/tasks/mine-transaction-worker.ts (2)

312-318: Minor: clarify units in constant names

BASE_POLL_INTERVAL_MS and MAX_POLL_INTERVAL_MS are correct, but SCALING_FACTOR is unit-less.
Consider renaming the first two to *_MS only after multiplying by 1000 to avoid confusion, e.g.:

-const MAX_POLL_INTERVAL_MS =
-  env.EXPERIMENTAL__MINE_WORKER_MAX_POLL_INTERVAL_SECONDS * 1000;
-const BASE_POLL_INTERVAL_MS =
-  env.EXPERIMENTAL__MINE_WORKER_BASE_POLL_INTERVAL_SECONDS * 1000;
+const MAX_POLL_INTERVAL_MS =
+  env.EXPERIMENTAL__MINE_WORKER_MAX_POLL_INTERVAL_SECONDS * 1_000;
+const BASE_POLL_INTERVAL_MS =
+  env.EXPERIMENTAL__MINE_WORKER_BASE_POLL_INTERVAL_SECONDS * 1_000;

Purely cosmetic, but helps readability.


327-330: Comment no longer accurate after env-driven back-off

The inline comment still states 2s, 4s, 6s … but the actual numbers depend on env vars.
Update it to avoid misleading future maintainers.

-// Retries at 2s, 4s, 6s, ..., 18s, 20s, 20s, 20s, ...
+// Retries at (attempts × BASE_POLL_INTERVAL_MS × SCALING_FACTOR) capped by MAX_POLL_INTERVAL_MS.
src/server/routes/backend-wallet/transfer.ts (1)

157-173: Consistent override handling & optional params

  1. txOverrides is forwarded raw, while the native-token path uses parseTransactionOverrides. Consider normalising both for consistency.

  2. Repeat of unchecked accountFactoryAddress as above.

  3. Minor typo: parameter ordering (fromAddress, toAddress) is fine but walletAddress is already checksumed; the extra conversion is harmless but redundant.

These are small, but aligning both branches will reduce subtle discrepancies.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fa4369a and 9a0c307.

📒 Files selected for processing (3)
  • src/server/routes/backend-wallet/transfer.ts (5 hunks)
  • src/shared/utils/env.ts (2 hunks)
  • src/worker/tasks/mine-transaction-worker.ts (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/worker/tasks/mine-transaction-worker.ts (1)
src/shared/utils/env.ts (1)
  • env (23-178)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: build
  • GitHub Check: lint
  • GitHub Check: Analyze (javascript-typescript)

Comment on lines 163 to +169
ACCOUNT_CACHE_SIZE: process.env.ACCOUNT_CAHCE_SIZE,
EXPERIMENTAL__MINE_WORKER_BASE_POLL_INTERVAL_SECONDS:
process.env.EXPERIMENTAL__MINE_WORKER_BASE_POLL_INTERVAL_SECONDS,
EXPERIMENTAL__MINE_WORKER_MAX_POLL_INTERVAL_SECONDS:
process.env.EXPERIMENTAL__MINE_WORKER_MAX_POLL_INTERVAL_SECONDS,
EXPERIMENTAL__MINE_WORKER_POLL_INTERVAL_SCALING_FACTOR:
process.env.EXPERIMENTAL__MINE_WORKER_POLL_INTERVAL_SCALING_FACTOR,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Typo in runtimeEnvStrict key prevents variable exposure

ACCOUNT_CAHCE_SIZE is misspelled; the schema key is ACCOUNT_CACHE_SIZE.
Because of the typo, the value will always be undefined, silently falling back to the default.

-    ACCOUNT_CACHE_SIZE: process.env.ACCOUNT_CAHCE_SIZE,
+    ACCOUNT_CACHE_SIZE: process.env.ACCOUNT_CACHE_SIZE,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ACCOUNT_CACHE_SIZE: process.env.ACCOUNT_CAHCE_SIZE,
EXPERIMENTAL__MINE_WORKER_BASE_POLL_INTERVAL_SECONDS:
process.env.EXPERIMENTAL__MINE_WORKER_BASE_POLL_INTERVAL_SECONDS,
EXPERIMENTAL__MINE_WORKER_MAX_POLL_INTERVAL_SECONDS:
process.env.EXPERIMENTAL__MINE_WORKER_MAX_POLL_INTERVAL_SECONDS,
EXPERIMENTAL__MINE_WORKER_POLL_INTERVAL_SCALING_FACTOR:
process.env.EXPERIMENTAL__MINE_WORKER_POLL_INTERVAL_SCALING_FACTOR,
ACCOUNT_CACHE_SIZE: process.env.ACCOUNT_CACHE_SIZE,
EXPERIMENTAL__MINE_WORKER_BASE_POLL_INTERVAL_SECONDS:
process.env.EXPERIMENTAL__MINE_WORKER_BASE_POLL_INTERVAL_SECONDS,
EXPERIMENTAL__MINE_WORKER_MAX_POLL_INTERVAL_SECONDS:
process.env.EXPERIMENTAL__MINE_WORKER_MAX_POLL_INTERVAL_SECONDS,
EXPERIMENTAL__MINE_WORKER_POLL_INTERVAL_SCALING_FACTOR:
process.env.EXPERIMENTAL__MINE_WORKER_POLL_INTERVAL_SCALING_FACTOR,
🤖 Prompt for AI Agents
In src/shared/utils/env.ts around lines 163 to 169, the key ACCOUNT_CAHCE_SIZE
is misspelled and should be corrected to ACCOUNT_CACHE_SIZE to match the schema.
Fix the typo by renaming ACCOUNT_CAHCE_SIZE to ACCOUNT_CACHE_SIZE so the
environment variable is properly read and not undefined.

Comment on lines +106 to +115
EXPERIMENTAL__MINE_WORKER_BASE_POLL_INTERVAL_SECONDS: z.coerce
.number()
.default(2),
EXPERIMENTAL__MINE_WORKER_MAX_POLL_INTERVAL_SECONDS: z.coerce
.number()
.default(20),
EXPERIMENTAL__MINE_WORKER_POLL_INTERVAL_SCALING_FACTOR: z.coerce
.number()
.gt(0.0, "scaling factor must be greater than 0")
.default(1.0),
Copy link

@coderabbitai coderabbitai bot Jun 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Validate base ≤ max & keep variables coherent

The schema allows a configuration where EXPERIMENTAL__MINE_WORKER_BASE_POLL_INTERVAL_SECONDS is larger than EXPERIMENTAL__MINE_WORKER_MAX_POLL_INTERVAL_SECONDS, producing a negative‐growth back-off once the Math.min cap kicks in.
Consider adding a cross-field refinement to guarantee base ≤ max, and possibly an upper bound for the scaling factor to avoid runaway delays.

 EXPERIMENTAL__MINE_WORKER_MAX_POLL_INTERVAL_SECONDS: z.coerce
   .number()
   .default(20),
 EXPERIMENTAL__MINE_WORKER_POLL_INTERVAL_SCALING_FACTOR: z.coerce
   .number()
   .gt(0.0, "scaling factor must be greater than 0")
   .default(1.0),
+}).refine(
+  (e) =>
+    e.EXPERIMENTAL__MINE_WORKER_BASE_POLL_INTERVAL_SECONDS <=
+    e.EXPERIMENTAL__MINE_WORKER_MAX_POLL_INTERVAL_SECONDS,
+  {
+    message: "BASE_POLL_INTERVAL_SECONDS must not exceed MAX_POLL_INTERVAL_SECONDS",
+    path: [
+      "EXPERIMENTAL__MINE_WORKER_BASE_POLL_INTERVAL_SECONDS",
+      "EXPERIMENTAL__MINE_WORKER_MAX_POLL_INTERVAL_SECONDS",
+    ],
+  },
 )
🤖 Prompt for AI Agents
In src/shared/utils/env.ts around lines 106 to 115, the environment variable
schema allows the base poll interval to be larger than the max poll interval,
which can cause incorrect back-off behavior. Add a cross-field refinement to the
schema that validates EXPERIMENTAL__MINE_WORKER_BASE_POLL_INTERVAL_SECONDS is
less than or equal to EXPERIMENTAL__MINE_WORKER_MAX_POLL_INTERVAL_SECONDS. Also,
add an upper bound constraint to
EXPERIMENTAL__MINE_WORKER_POLL_INTERVAL_SCALING_FACTOR to prevent excessively
large scaling factors.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

base can be greater than max, combined with a low scaling factor this actually makes sense

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@d4mr Thank you for the clarification! You're absolutely right - that's actually a clever configuration pattern. With a low scaling factor, having base > max allows for fine-grained control over the backoff curve. For example, if base=30, max=20, and scaling_factor=0.1, the intervals would be 3s, 6s, 9s, etc., gradually ramping up until hitting the 20s cap. This gives much more granular control over the polling behavior than I initially realized.

I appreciate you explaining the intended design - it makes perfect sense now!

ʕ •ᴥ•ʔ Thanks for teaching me something new!


✏️ Learnings added
Learnt from: d4mr
PR: thirdweb-dev/engine#897
File: src/shared/utils/env.ts:106-115
Timestamp: 2025-06-09T23:36:29.115Z
Learning: In the mine worker polling configuration, EXPERIMENTAL__MINE_WORKER_BASE_POLL_INTERVAL_SECONDS can intentionally be set higher than EXPERIMENTAL__MINE_WORKER_MAX_POLL_INTERVAL_SECONDS when combined with a low EXPERIMENTAL__MINE_WORKER_POLL_INTERVAL_SCALING_FACTOR. This creates a gradual backoff curve where the actual interval starts low (base * attempts * scaling_factor) and ramps up until capped by the max value, allowing for fine-grained control over polling behavior.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Comment on lines +15 to +17
getChecksumAddress,
normalizeAddress,
} from "../../../shared/utils/primitive-types";
Copy link

@coderabbitai coderabbitai bot Jun 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Guard optional AA headers before checksum conversion

accountFactoryAddress can be undefined, yet getChecksumAddress is called unconditionally when accountAddress is present, causing a runtime error.

-                accountFactoryAddress: getChecksumAddress(
-                  accountFactoryAddress,
-                ),
+                ...(accountFactoryAddress
+                  ? { accountFactoryAddress: getChecksumAddress(accountFactoryAddress) }
+                  : {}),

Apply the same check in the ERC20 branch below.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/server/routes/backend-wallet/transfer.ts around lines 15 to 17, the
function getChecksumAddress is called on accountFactoryAddress without checking
if it is undefined, which can cause a runtime error. To fix this, add a guard
condition to verify that accountFactoryAddress is defined before calling
getChecksumAddress on it. Apply this same conditional check in the ERC20 branch
where getChecksumAddress is used on accountFactoryAddress to prevent similar
errors.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

export function getChecksumAddress(
  val?: string | Address | null,
): Address | undefined {
  return val ? checksumAddress(val) : undefined;
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@d4mr Thank you for showing the implementation! You're absolutely right - getChecksumAddress safely handles undefined values by returning undefined when the input is falsy. The original concern about runtime errors was based on an incorrect assumption about the function's behavior.

The function signature val?: string | Address | null and the implementation return val ? checksumAddress(val) : undefined clearly show it's designed to handle optional values gracefully.


✏️ Learnings added
Learnt from: d4mr
PR: thirdweb-dev/engine#897
File: src/server/routes/backend-wallet/transfer.ts:15-0
Timestamp: 2025-06-09T23:37:07.284Z
Learning: The `getChecksumAddress` function in this codebase safely handles undefined/null values by accepting `val?: string | Address | null` and returning `Address | undefined`. It returns `undefined` when passed falsy values, so calling it on potentially undefined values like `accountFactoryAddress` does not cause runtime errors.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

} from "../../../shared/utils/primitive-types";
import { thirdwebClient } from "../../../shared/utils/sdk";
import { insertTransaction } from "../../../shared/utils/transaction/insert-transaction";
import { queueTransaction } from "../../../shared/utils/transaction/queue-transation";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Import path typo breaks compilation

queue-transation is missing the second “c”.

-import { queueTransaction } from "../../../shared/utils/transaction/queue-transation";
+import { queueTransaction } from "../../../shared/utils/transaction/queue-transaction";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { queueTransaction } from "../../../shared/utils/transaction/queue-transation";
import { queueTransaction } from "../../../shared/utils/transaction/queue-transaction";
🤖 Prompt for AI Agents
In src/server/routes/backend-wallet/transfer.ts at line 20, the import path for
queueTransaction has a typo: "queue-transation" should be corrected to
"queue-transaction". Fix the import statement by adding the missing "c" to the
folder name to resolve the compilation error.

@d4mr d4mr merged commit 4851842 into main Jun 9, 2025
8 checks passed
@d4mr d4mr deleted the pb/transfer-aa-fixes branch June 9, 2025 23:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants