Skip to content

ci: enforce LibAsset routing for ERC20 transfers - #1900

Merged
0xDEnYO merged 3 commits into
mainfrom
feature/exsc-300-add-solhint-rule-or-ci-grep-enforcing-libasset-routing-for
Jun 12, 2026
Merged

0xDEnYO merged 3 commits into
mainfrom
feature/exsc-300-add-solhint-rule-or-ci-grep-enforcing-libasset-routing-for

Conversation

@0xDEnYO

@0xDEnYO 0xDEnYO commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Which Linear task belongs to this PR?

EXSC-300 — Add solhint rule (or CI grep) enforcing LibAsset routing for ERC20 transfers

Audit follow-up to PR #1715 (Sujith, informational finding #4).

Why did I implement it this way?

The ticket offered two options: a custom solhint rule or a CI grep step. I went with the CI grep step (a new workflow, enforceLibAssetRouting.yml):

  • A custom solhint rule would require shipping a local JS solhint plugin package (solhint-plugin-*), which conflicts with the repo's TypeScript/Bash-only scripting rule and adds dependency surface for a single rule.
  • The grep backstop is explicitly sanctioned by the ticket as "adequate", is trivially auditable, and follows the established house pattern of inline-bash checker workflows (jsonChecker.yml, protectSecurityRelevantCode.yml).

Behavior:

  • Fails CI if any .sol file in src/ outside the allowlist contains .safeTransfer( or .safeTransferFrom(.
  • safeTransferETH( is not matched and remains allowed everywhere (the regex requires ( directly after safeTransfer/safeTransferFrom).
  • The four packed facets (HopFacetPacked, AcrossFacetPacked, CBridgeFacetPacked, AcrossFacetPackedV3) are explicitly allowlisted with a comment, per the AC.
  • Beyond the four facets named in the AC, six more pre-existing offenders exist on main (TokenWrapper, LiFiDEXAggregator, ReceiverStargateV2, ReceiverAcrossV3, ReceiverChainflip, WithdrawablePeriphery — consistent with the audit finding "Out-of-scope facets and LidoWrapper bypass LibAsset"). They are grandfathered in a separately-commented allowlist section so the check is green on main from day one while still rejecting any NEW file or any new call site in a currently-clean file.

Verification evidence (run locally against this branch):

  • bash -n on the extracted check script: pass
  • Clean tree (current src/): exit 0
  • Injected src/EvilFacet.sol with IERC20(t).safeTransfer(...): exit 1, offending file + line printed
  • Injected src/EthOnlyFacet.sol with only safeTransferETH calls (both method-style and library-style): exit 0
  • bunx prettier --check on the workflow file: pass

DRAFT status / pr-ready note

/pr-ready (local CodeRabbit) could not be run to a clean state: the CLI returned "Review limit reached" (org usage credits exhausted), twice. Per the pre-PR workflow this PR is therefore opened as a draft; cloud CodeRabbit will review on this PR as the safety net. A self-review-pass sweep (mechanical/semantic/executable) was completed with no findings.

Checklist before requesting a review

  • I have performed a self-review of my code
  • This pull request is as small as possible and only tackles one problem
  • I have run /pr-ready (local CodeRabbit) on this branch and resolved (or explicitly documented) all findings — see .agents/commands/pr-ready.md (attempted; rate-limited — documented above)
  • I have added tests that cover the functionality / test the bug (manual positive/negative/exemption runs of the check script, evidence above; no Solidity changes)
  • For new facets: I have checked all points from this list: https://www.notion.so/lifi/New-Facet-Contract-Checklist-157f0ff14ac78095a2b8f999d655622e (N/A — no facets touched)
  • I have updated any required documentation (workflow header documents purpose, triggers, behavior, limitations)

Checklist for reviewer (DO NOT DEPLOY and contracts BEFORE CHECKING THIS!!!)

  • I have checked that any arbitrary calls to external contracts are validated and or restricted
  • I have checked that any privileged calls (i.e. storage modifications) are validated and or restricted
  • I have ensured that any new contracts have had AT A MINIMUM 1 preliminary audit conducted on by <company/auditor>

🤖 Generated with Claude Code

Adds a CI grep check (audit follow-up, Sujith finding #4 on PR #1715)
that fails any PR introducing direct .safeTransfer( / .safeTransferFrom(
calls in src/ outside LibAsset and an explicit allowlist of pre-existing
offenders. Native-ETH safeTransferETH calls remain allowed.

EXSC-300

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 10, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@0xDEnYO, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 16 minutes and 52 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more credits in the billing tab to continue.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a1126026-9e77-4851-a8df-cec1a14b0f50

📥 Commits

Reviewing files that changed from the base of the PR and between 4ea9719 and 88ad831.

📒 Files selected for processing (1)
  • .github/workflows/enforceLibAssetRouting.yml

Walkthrough

This PR adds a new GitHub Actions workflow that enforces ERC20 transfer routing through LibAsset. The workflow scans all Solidity files in src/ for direct .safeTransfer(), .transfer(), .safeTransferFrom(), and .transferFrom() calls, excludes .safeTransferETH(), compares findings against a hardcoded allowlist, and fails the build with annotated violations if matches occur outside permitted files.

Changes

ERC20 Transfer Routing Enforcement

Layer / File(s) Summary
CI workflow for LibAsset transfer routing validation
.github/workflows/enforceLibAssetRouting.yml
GitHub Actions workflow enforces that ERC20 transfers bypass direct calls and route through LibAsset by scanning sources for transfer patterns against an allowlist, failing the build with match details on violations.

🎯 2 (Simple) | ⏱️ ~8 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main change: adding a CI workflow to enforce LibAsset routing for ERC20 transfers, which is the core purpose of this pull request.
Description check ✅ Passed The description comprehensively addresses the template sections including the Linear task link, detailed implementation rationale, and a thorough checklist with self-review completion and documentation of rate-limit constraints.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/exsc-300-add-solhint-rule-or-ci-grep-enforcing-libasset-routing-for

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@0xDEnYO
0xDEnYO marked this pull request as ready for review June 10, 2026 11:20
@lifi-action-bot lifi-action-bot changed the title ci: enforce LibAsset routing for ERC20 transfers [EXSC-300] ci: enforce LibAsset routing for ERC20 transfers Jun 10, 2026
@0xDEnYO
0xDEnYO enabled auto-merge (squash) June 11, 2026 04:18
Comment thread .github/workflows/enforceLibAssetRouting.yml
Comment thread .github/workflows/enforceLibAssetRouting.yml Outdated
Review feedback: the regex only caught SafeTransferLib-style calls, so raw
IERC20.transfer/.transferFrom (the original Tron USDT bug class) passed
silently - including LidoWrapper.sol, the contract explicitly named in
audit finding #4. Widen the pattern and allowlist LidoWrapper (grandfathered)
and Executor (false positive: transferFrom on our own ERC20Proxy).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
.github/workflows/enforceLibAssetRouting.yml (1)

28-30: ⚡ Quick win

Harden checkout by disabling credential persistence

At Line 29, actions/checkout should set persist-credentials: false since this job only performs local grep scans and does not need authenticated git operations after checkout.

Suggested patch
       - name: Checkout code
         uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+        with:
+          persist-credentials: false

Based on learnings from static analysis, this maps to the reported artipacked credential-persistence warning.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/enforceLibAssetRouting.yml around lines 28 - 30, The
checkout step using actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
should be hardened by disabling credential persistence; update the checkout step
(the actions/checkout invocation) to include persist-credentials: false so
credentials are not retained in the runner after checkout for this local grep
scan job.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In @.github/workflows/enforceLibAssetRouting.yml:
- Around line 28-30: The checkout step using
actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 should be hardened by
disabling credential persistence; update the checkout step (the actions/checkout
invocation) to include persist-credentials: false so credentials are not
retained in the runner after checkout for this local grep scan job.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: ff43e899-0d32-49d5-a462-d03e0343eb99

📥 Commits

Reviewing files that changed from the base of the PR and between 3c5e9d7 and 4ea9719.

📒 Files selected for processing (1)
  • .github/workflows/enforceLibAssetRouting.yml

The job only runs local grep scans and needs no authenticated git
operations after checkout (CodeRabbit finding; matches house style in
other workflows).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@0xDEnYO

0xDEnYO commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai The persist-credentials: false nitpick is addressed in 88ad831.

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

@0xDEnYO Thanks for the update! Confirmed — the persist-credentials: false addition in commit 88ad831 is the right fix to prevent the checkout token from being forwarded into subsequent steps.

🐇✨


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

@0xDEnYO
0xDEnYO merged commit fff7cd1 into main Jun 12, 2026
32 of 33 checks passed
@0xDEnYO
0xDEnYO deleted the feature/exsc-300-add-solhint-rule-or-ci-grep-enforcing-libasset-routing-for branch June 12, 2026 07:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants