Skip to content

EXSC-241 Fix Tron USDT transfers + switch to granural whitelist [GenericSwapFacetV3 v2.0.0, PolymerCCTPFacet v2.0.0, WithdrawablePeriphery v2.0.0, LibAsset v2.2.0, LiFiDEXAggregator v1.13.0]#1715

Open
mirooon wants to merge 11 commits intomainfrom
exsc-241-fix-tron-usdt-transfers

Conversation

@mirooon
Copy link
Copy Markdown
Contributor

@mirooon mirooon commented Apr 15, 2026

Which Linear task belongs to this PR?

https://linear.app/lifi-linear/issue/EXSC-241/fix-tron-usdt-transfers-failing-on-safetransferlib-return-data-check

Why did I implement it this way?

Problem

Tron’s canonical USDT contract
(TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t / 0xa614f803B6FD780986A42c78Ec9c7f77e6DeD13C)
was compiled with an older Solidity version (~0.4.x).

Although its transfer() function is declared as returns (bool), it does not explicitly return true. As a result:

  • The transfer executes successfully and balances update correctly.

  • However, the return data contains 32 zero bytes (false) instead of:

    • no return data (non-standard tokens), or
    • true (standard ERC20 behavior).

This creates incompatibility with SafeTransferLib.safeTransfer, which enforces strict return validation:

  • Accepts:

    • returndatasize() == 0, or
    • return value == 1
  • Rejects:

    • return value == 0 → reverts with TransferFailed

Impact:
All outbound transfer() calls to Tron USDT reverted inside our contracts (via LibAsset.transferERC20SafeTransferLib.safeTransfer), even though the transfer itself succeeded.

Important:
transferFrom() is not affected — Tron USDT correctly returns true.
Inbound flows using transferFrom() remain safe.


Solution

A targeted exception was introduced in LibAsset.transferERC20:

  • Detect:

    • Tron mainnet (chainId = 728126428)
    • Canonical USDT address
  • In this specific case:

    • Use a direct IERC20.transfer() call
    • Skip SafeTransferLib return-data validation
  • Still:

    • Propagate any revert from the token contract

All other tokens and chains continue to use SafeTransferLib.safeTransfer unchanged.


What Was Done

Core Fix

  • src/Libraries/LibAsset.sol (v2.2.0)

    • Added TRON_CHAIN_ID and TRON_USDT constants
    • Updated transferERC20 to apply the bypass only for Tron USDT

Breaking Changes

  • src/Facets/GenericSwapFacetV3.sol (v2.0.0)

  • Main changes:
    The migration to LibAsset.transferERC20 ensures the Tron USDT fix is applied consistently.

    * From: manual `safeApprove(0)` → `safeApprove(max)`
    * To: `LibAsset.maxApproveERC20`
    

    This release introduces a breaking security model change. As this update already required changes to GenericSwapFacetV3, I used the opportunity to consolidate improvements and minimize audit overhead by batching them into a single audit cycle.

As part of this, the facet was migrated to the new whitelisting model:

* **Before:**
  `contractIsAllowed(callTo)` AND `selectorIsAllowed(selector)`
  (independent allowlists)
* **After:**
  `contractSelectorIsAllowed(callTo, selector)`
  (explicit `(contract, selector)` pair required)
  • Additional changes:

    • Introduced APPROVE_TO_ONLY_SELECTOR = 0xffffffff sentinel for approve-only targets
    • Approval logic migrated:

  • src/Helpers/WithdrawablePeriphery.sol (v2.0.0)

    Two breaking changes:

    1. Added explicit validation:
      • if (amount == 0) revert ZeroAmount()
    2. Error handling change:
      • Removed ExternalCallFailed
      • Replaced with ETHTransferFailed on native transfer failure

Other Contract Updates

  • src/Periphery/LiFiDEXAggregator.sol (v1.13.0)

    • Migrated all ERC20 transfer / transferFrom calls to:

      • LibAsset.transferERC20
      • LibAsset.transferFromERC20
  • src/Helpers/WithdrawablePeriphery.sol

    • withdrawToken now uses LibAsset.transferERC20

Tests & Tooling

  • Added MockTronUSDT contract reproducing the faulty return behavior (transfer() returns false)

  • Added Tron-specific LibAsset test suite:

    • Validates bypass logic
    • Confirms standard tokens still use SafeTransferLib
  • Updated multiple receiver test files due to error selector changes

  • Added/updated internal guidelines:

    • Versioning rules in .cursor/rules/100-solidity-basics.mdc
    • Test naming conventions in .cursor/rules/400-solidity-tests.mdc

Contracts Not Modified

  • src/Periphery/TokenWrapper.sol

    • Not affected — only wraps native assets (e.g., WETH), never Tron USDT
  • src/Periphery/LidoWrapper.sol

    • Not affected — operates exclusively on stETH/wstETH, which are Ethereum-only assets.
  • Receiver Contracts

    • ReceiverAcrossV3.sol
    • ReceiverChainflip.sol
    • ReceiverStargateV2.sol

    Not modified because:

    • They are not deployed on Tron
    • No current plans to deploy them there

    Note:
    If deployed on Tron in the future:

    • Outbound transfer() must route through LibAsset.transferERC20
    • transferFrom() usage remains safe (returns true on Tron USDT)

Checklist before requesting a review

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>

@lifi-action-bot lifi-action-bot marked this pull request as draft April 15, 2026 15:09
@lifi-action-bot lifi-action-bot changed the title EXSC-241 Fix Tron USDT transfers EXSC-241 Fix Tron USDT transfers [GenericSwapFacetV3 v1.1.0, WithdrawablePeriphery v1.0.1, LibAsset v2.2.0, LiFiDEXAggregator v1.13.0] Apr 15, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 15, 2026

Walkthrough

Consolidates ERC20 transfers/approvals to LibAsset helpers across facets and periphery, special-cases Tron USDT in LibAsset with new constants and tests, tightens Solidity test naming rules, updates multiple tests to expect ETHTransferFailed, adds MockTronUSDT test-double, and bumps several @custom:version annotations.

Changes

Cohort / File(s) Summary
Test Naming Rules
\.cursor/rules/400-solidity-tests.mdc
Expanded/prescriptive test naming: require testRevert_ for revert-expecting tests, enforce PascalCase segments after prefixes, restrict underscore usage, and require aligning short/ambiguous test names when editing test files.
Solidity Baseline Rules
\.cursor/rules/100-solidity-basics.mdc
Forbid comments/directives between SPDX and pragma; require NatSpec directly above contract/interface; add @custom:version requirement and semantic bump rules.
Generic Swap & Approvals
src/Facets/GenericSwapFacetV3.sol
Switched ERC20 interactions to IERC20 + LibAsset helpers; unified allowlist checks via LibAllowList.contractSelectorIsAllowed(callTo, selector); use unconditional LibAsset.maxApproveERC20 per leg; refactored slippage refund and bumped version to 2.0.0.
Periphery Withdrawals & Receivers
src/Helpers/WithdrawablePeriphery.sol, test/solidity/Helpers/WithdrawablePeriphery.t.sol, test/solidity/Periphery/...
Replaced SafeTransferLib/native branching with LibAsset.transferAsset; revert only on zero amount (ZeroAmount); updated NatSpec and version; tests updated to expect ETHTransferFailed and added zero-amount revert test.
DEX Aggregator Transfers
src/Periphery/LiFiDEXAggregator.sol
Removed using SafeERC20; replaced safeTransfer/safeTransferFrom calls with LibAsset.transferERC20/transferFromERC20; retained ETH flows; bumped version metadata.
LibAsset Enhancements
src/Libraries/LibAsset.sol, test/solidity/Libraries/LibAsset.t.sol
Bumped library version to 2.2.0; added TRON_CHAIN_ID and TRON_USDT constants; transferERC20 special-cases Tron mainnet USDT to use non-standard transfer return behavior; tests extended to cover Tron scenarios and added a wrapper in implementer.
Mock Tron USDT Test Double
test/solidity/utils/MockTronUSDT.sol
Added MockTronUSDT that mimics legacy Tron USDT (returns false from transfer after state changes), with mint/transfer/transferFrom/approve and custom errors.
Other Tests: Revert Selectors & Naming
test/solidity/Periphery/..., test/solidity/Periphery/Across/..., test/solidity/Periphery/ReceiverOIF.t.sol
Updated multiple tests to expect ETHTransferFailed() instead of ExternalCallFailed(); minor test renames to align with naming conventions and new error selectors.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description check ✅ Passed The PR description comprehensively covers the problem, solution, and all breaking changes with clear rationale and testing notes.
Title check ✅ Passed The title accurately summarizes the main changes: fixing Tron USDT transfers and switching to granular whitelist, with version bumps for affected contracts.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch exsc-241-fix-tron-usdt-transfers

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.

@lifi-action-bot
Copy link
Copy Markdown
Collaborator

lifi-action-bot commented Apr 15, 2026

Test Coverage Report

Line Coverage: 88.03% (3223 / 3661 lines)
Function Coverage: 90.82% ( 495 / 545 functions)
Branch Coverage: 70.77% ( 591 / 835 branches)
Test coverage (88.03%) is above min threshold (83%). Check passed.

@mirooon mirooon marked this pull request as ready for review April 15, 2026 15:16
@lifi-action-bot
Copy link
Copy Markdown
Collaborator

lifi-action-bot commented Apr 15, 2026

🤖 GitHub Action: Security Alerts Review 🔍

🟢 Dismissed Security Alerts with Comments
The following alerts were dismissed with proper comments:

🟢 View Alert - File: src/Helpers/WithdrawablePeriphery.sol
🔹 Parameters passed to a constructor that are not validated for correct values may lead to contract creation in an undesired state. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/no-parameter-validation-in-constructor
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: Mostly as a style / deployment-safety nit, not as a meaningful exploit. We usually check owner in the child contract of WithdrawablePeriphery

🟢 View Alert - File: src/Facets/GenericSwapFacetV3.sol
🔹 Performing a narrowing downcast may result in silent overflow due to bit truncation. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unsafe-downcast
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: normal, correct way to read an ABI function selector: the first four bytes of callData are exactly a bytes4. There is no extra width to “overflow”; the conversion is intentional use of those four bytes as the selector.

🟢 View Alert - File: src/Helpers/WithdrawablePeriphery.sol
🔹 Making an external call without a gas budget may consume all of the transaction's gas, causing it to revert. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/call-without-gas-budget
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: withdrawToken is onlyOwner, so a malicious receiver can’t grief arbitrary users; the owner can pick a different _receiver if one reverts and the contract no longer does receiver.call{value: ...}("");

🟢 View Alert - File: src/Periphery/LiFiDEXAggregator.sol
🔹 External calls in a loop may lead to denial of service if those calls revert. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/calls-in-loop
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: swaps/wraps necessarily perform external calls per step, and if any step reverts the whole route reverts (atomicity)

🟢 View Alert - File: src/Helpers/WithdrawablePeriphery.sol
🔹 Reentrant functions which emit events after making an external call may lead to out-of-order events. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/reentrancy-events
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: it's safe, it's only admin function

🟢 View Alert - File: src/Helpers/WithdrawablePeriphery.sol
🔹 Functions restricted to a single owner may result in loss or abuse of contract functionality if the owner's private key is compromised. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/owner-single-point-of-failure
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: it's managed by multisig

🟢 View Alert - File: src/Facets/GenericSwapFacetV3.sol
🔹 Performing a narrowing downcast may result in silent overflow due to bit truncation. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unsafe-downcast
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: normal, correct way to read an ABI function selector: the first four bytes of callData are exactly a bytes4. There is no extra width to “overflow”; the conversion is intentional use of those four bytes as the selector.

🟢 View Alert - File: src/Facets/GenericSwapFacetV3.sol
🔹 Reentrant functions which emit events after making an external call may lead to out-of-order events. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/reentrancy-events
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: callTo / approveTo are gated by LibAllowList. those callees are known routers

🟢 View Alert - File: src/Facets/GenericSwapFacetV3.sol
🔹 Reentrant functions which emit events after making an external call may lead to out-of-order events. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/reentrancy-events
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: callTo / approveTo are gated by LibAllowList. those callees are known routers

🟢 View Alert - File: src/Facets/GenericSwapFacetV3.sol
🔹 Reentrant functions which emit events after making an external call may lead to out-of-order events. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/reentrancy-events
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: callTo / approveTo are gated by LibAllowList. those callees are known routers

🟢 View Alert - File: src/Facets/GenericSwapFacetV3.sol
🔹 Reentrant functions which emit events after making an external call may lead to out-of-order events. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/reentrancy-events
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: callTo / approveTo are gated by LibAllowList. those callees are known routers

🟢 View Alert - File: src/Facets/GenericSwapFacetV3.sol
🔹 Parameters passed to a constructor that are not validated for correct values may lead to contract creation in an undesired state. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/no-parameter-validation-in-constructor
🔹 Dismiss Reason: Won't fix
🔹 Dismiss Comment: that's valid alert. It will be addressed in the next PR.

🟢 View Alert - File: src/Facets/GenericSwapFacetV3.sol
🔹 Reentrant functions which emit events after making an external call may lead to out-of-order events. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/reentrancy-events
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: This function is not vulnerable to reentrancy. All external calls are made to whitelisted DEX contracts using a controlled low-level .call

🟢 View Alert - File: src/Facets/GenericSwapFacetV3.sol
🔹 Reentrant functions which emit events after making an external call may lead to out-of-order events. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/reentrancy-events
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: Event emissions follow all state mutations and validations

🟢 View Alert - File: src/Facets/GenericSwapFacetV3.sol
🔹 Making an external call without a gas budget may consume all of the transaction's gas, causing it to revert. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/call-without-gas-budget
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: This call intentionally sends native tokens using .call without a specific gas stipend because we are forwarding the full balance and handling failure with an explicit revert. The callee (receiver) is trusted and failures are caught via if (!success)

🟢 View Alert - File: src/Facets/GenericSwapFacetV3.sol
🔹 Making an external call without a gas budget may consume all of the transaction's gas, causing it to revert. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/call-without-gas-budget
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: We explicitly check the success and the _receiver is user supplied

🟢 View Alert - File: src/Facets/GenericSwapFacetV3.sol
🔹 Making an external call without a gas budget may consume all of the transaction's gas, causing it to revert. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/call-without-gas-budget
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: it executes a user-defined swap on a whitelisted contract and selector (LibAllowList)

🟢 View Alert - File: src/Facets/GenericSwapFacetV3.sol
🔹 Making an external call without a gas budget may consume all of the transaction's gas, causing it to revert. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/call-without-gas-budget
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: This function is not vulnerable to reentrancy. All external calls are made to whitelisted DEX contracts using a controlled low-level .call

🟢 View Alert - File: src/Facets/GenericSwapFacetV3.sol
🔹 Making an external call without a gas budget may consume all of the transaction's gas, causing it to revert. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/call-without-gas-budget
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: The target contract and selector are both whitelisted via LibAllowList to mitigate risk

🟢 View Alert - File: src/Facets/GenericSwapFacetV3.sol
🔹 Making an external call without a gas budget may consume all of the transaction's gas, causing it to revert. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/call-without-gas-budget
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: The target contract and selector are both whitelisted via LibAllowList to mitigate risk

🟢 View Alert - File: src/Facets/GenericSwapFacetV3.sol
🔹 Making an external call without a gas budget may consume all of the transaction's gas, causing it to revert. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/call-without-gas-budget
🔹 Dismiss Reason: Won't fix
🔹 Dismiss Comment: This native token transfer uses .call to avoid the 2300 gas stipend limitation of transfer() and send(), which is incompatible with many smart contract wallets. We explicitly check the success flag and revert with a custom error if the call fails

🟢 View Alert - File: src/Facets/GenericSwapFacetV3.sol
🔹 External calls in a loop may lead to denial of service if those calls revert. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/calls-in-loop
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: We explicitly check the success and receiver is user supplied

🟢 View Alert - File: src/Facets/GenericSwapFacetV3.sol
🔹 External calls in a loop may lead to denial of service if those calls revert. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/calls-in-loop
🔹 Dismiss Reason: Won't fix
🔹 Dismiss Comment: if one swap fails, the whole transaction should revert, and that's acceptable by design

🟢 View Alert - File: src/Facets/GenericSwapFacetV3.sol
🔹 External calls in a loop may lead to denial of service if those calls revert. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/calls-in-loop
🔹 Dismiss Reason: Won't fix
🔹 Dismiss Comment: if one swap fails, the whole transaction should revert, and that's acceptable by design

🟢 View Alert - File: src/Periphery/LiFiDEXAggregator.sol
🔹 Casting a large uint to int (even at same byte width) may lead to overflow. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/uint-to-int-conversion
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: safe. The amountIn value comes from the pool’s reserves, which are much smaller than the maximum number allowed by int256

🟢 View Alert - File: src/Periphery/LiFiDEXAggregator.sol
🔹 Calling a function without checking the return value may lead to silent failures. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/unused-return-function-call
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: The return value from IUniswapV3Pool(pool).swap() is not needed because the result is handled by the callback function uniswapV3SwapCallback

🟢 View Alert - File: src/Periphery/LiFiDEXAggregator.sol
🔹 External calls in a loop may lead to denial of service if those calls revert. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/calls-in-loop
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: expected and safe. If the call fails, the whole transaction reverts,

🟢 View Alert - File: src/Libraries/LibAsset.sol
🔹 Calling transferFrom functionality with a parameterized from value may lead to theft or loss of tokens. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/arbitrary-transfer-from
🔹 Dismiss Reason: Won't fix
🔹 Dismiss Comment: This is a library and it's by design that the function is generic.

🟢 View Alert - File: src/Libraries/LibAsset.sol
🔹 The value of msg.value is constant in a transaction, and will not be reapplied in a loop. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/msg-value-reuse
🔹 Dismiss Reason: Won't fix
🔹 Dismiss Comment: That's fine. We do not expect msg.value to change. Also, if we deposit a native asset we will only do it once so this should be fine.

🟢 View Alert - File: src/Periphery/LiFiDEXAggregator.sol
🔹 Parameters passed to a constructor that are not validated for correct values may lead to contract creation in an undesired state. For more information, visit: http://detectors.olympixdevsectools.com/article/web3-vulnerability/no-parameter-validation-in-constructor
🔹 Dismiss Reason: False positive
🔹 Dismiss Comment: The _owner is already validated in the constructor and the priviledged array t is optiona

No unresolved security alerts! 🎉

@lifi-action-bot lifi-action-bot marked this pull request as draft April 15, 2026 15:17
Copy link
Copy Markdown
Contributor

@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: 1

🧹 Nitpick comments (1)
test/solidity/Libraries/LibAsset.t.sol (1)

197-223: Align the last two test names with the rule you just tightened.

test_TronUsdtIsPresentAtCanonicalAddressAfterLocalStub and test_StablecoinTransferSucceedsTronChainId still lean on implementation detail / vague nouns more than the surrounding renamed tests. Renaming them to behavior-first names would avoid leaving mixed styles in the same file.

As per coding guidelines, "Avoid stuffing names with test mechanics ... unless two tests would otherwise be indistinguishable" and "When editing any test/**/*.t.sol file, align existing test names in that file to this convention if they are still short or ambiguous."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/solidity/Libraries/LibAsset.t.sol` around lines 197 - 223, Two tests use
implementation-detail names; rename function
test_TronUsdtIsPresentAtCanonicalAddressAfterLocalStub and
test_StablecoinTransferSucceedsTronChainId to behavior-first, descriptive names.
Update the declarations and any references so they describe observable behavior
(e.g., presence/availability and successful transfer on Tron chain) rather than
stubbing/chain-id mechanics; modify function names for the functions
test_TronUsdtIsPresentAtCanonicalAddressAfterLocalStub and
test_StablecoinTransferSucceedsTronChainId accordingly and keep assertions and
body unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/Helpers/WithdrawablePeriphery.sol`:
- Around line 2-3: Remove the stray `@custom:version` tag placed above the
pragma and instead add it into the contract's NatSpec block for
WithdrawablePeriphery (e.g., alongside `@title`) so the contract header includes
`@custom:version 1.0.1`; also ensure the file retains the SPDX comment followed
immediately by pragma with no blank line between them.

---

Nitpick comments:
In `@test/solidity/Libraries/LibAsset.t.sol`:
- Around line 197-223: Two tests use implementation-detail names; rename
function test_TronUsdtIsPresentAtCanonicalAddressAfterLocalStub and
test_StablecoinTransferSucceedsTronChainId to behavior-first, descriptive names.
Update the declarations and any references so they describe observable behavior
(e.g., presence/availability and successful transfer on Tron chain) rather than
stubbing/chain-id mechanics; modify function names for the functions
test_TronUsdtIsPresentAtCanonicalAddressAfterLocalStub and
test_StablecoinTransferSucceedsTronChainId accordingly and keep assertions and
body unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 8796d4cc-f146-42cc-9d5f-95e93dbd54e6

📥 Commits

Reviewing files that changed from the base of the PR and between 602d4a9 and dfef8b8.

📒 Files selected for processing (7)
  • .cursor/rules/400-solidity-tests.mdc
  • src/Facets/GenericSwapFacetV3.sol
  • src/Helpers/WithdrawablePeriphery.sol
  • src/Libraries/LibAsset.sol
  • src/Periphery/LiFiDEXAggregator.sol
  • test/solidity/Libraries/LibAsset.t.sol
  • test/solidity/utils/MockTronUSDT.sol

Comment thread src/Helpers/WithdrawablePeriphery.sol Outdated
@mirooon mirooon marked this pull request as ready for review April 16, 2026 08:06
@lifi-action-bot lifi-action-bot marked this pull request as draft April 16, 2026 08:06
Comment thread src/Facets/GenericSwapFacetV3.sol Dismissed
Copy link
Copy Markdown
Contributor

@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.

🧹 Nitpick comments (1)
src/Facets/GenericSwapFacetV3.sol (1)

9-9: Minor: Import ordering convention.

Per coding guidelines, external library imports should be grouped before local imports. The OpenZeppelin IERC20 import could be moved above the local ILiFi import. This is a minor stylistic note and doesn't affect functionality.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Facets/GenericSwapFacetV3.sol` at line 9, The import ordering in
GenericSwapFacetV3.sol should place external library imports before local
project imports; move the OpenZeppelin IERC20 import so it appears above the
local ILiFi import (i.e., ensure import { IERC20 } from "@openzeppelin/..."; is
listed before import { ILiFi } ...), keeping the same symbols and no other
changes to code or semantics.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/Facets/GenericSwapFacetV3.sol`:
- Line 9: The import ordering in GenericSwapFacetV3.sol should place external
library imports before local project imports; move the OpenZeppelin IERC20
import so it appears above the local ILiFi import (i.e., ensure import { IERC20
} from "@openzeppelin/..."; is listed before import { ILiFi } ...), keeping the
same symbols and no other changes to code or semantics.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: dfc5053d-a236-4515-9b45-f6a284908aa5

📥 Commits

Reviewing files that changed from the base of the PR and between dfef8b8 and ad14a6e.

📒 Files selected for processing (8)
  • .cursor/rules/100-solidity-basics.mdc
  • src/Facets/GenericSwapFacetV3.sol
  • src/Helpers/WithdrawablePeriphery.sol
  • test/solidity/Helpers/WithdrawablePeriphery.t.sol
  • test/solidity/Periphery/Across/V3/ReceiverAcrossV3.t.sol
  • test/solidity/Periphery/Across/V4/ReceiverAcrossV4.t.sol
  • test/solidity/Periphery/ReceiverOIF.t.sol
  • test/solidity/Periphery/ReceiverStargateV2.t.sol
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/Helpers/WithdrawablePeriphery.sol

@mirooon mirooon marked this pull request as ready for review April 16, 2026 12:00
@lifi-action-bot lifi-action-bot changed the title EXSC-241 Fix Tron USDT transfers [GenericSwapFacetV3 v1.1.0, WithdrawablePeriphery v1.0.1, LibAsset v2.2.0, LiFiDEXAggregator v1.13.0] EXSC-241 Fix Tron USDT transfers [GenericSwapFacetV3 v2.0.0, WithdrawablePeriphery v1.0.1, LibAsset v2.2.0, LiFiDEXAggregator v1.13.0] Apr 16, 2026
@lifi-action-bot lifi-action-bot marked this pull request as draft April 16, 2026 12:00
@mirooon mirooon marked this pull request as ready for review April 16, 2026 12:03
@lifi-action-bot lifi-action-bot changed the title EXSC-241 Fix Tron USDT transfers [GenericSwapFacetV3 v2.0.0, WithdrawablePeriphery v1.0.1, LibAsset v2.2.0, LiFiDEXAggregator v1.13.0] EXSC-241 Fix Tron USDT transfers [GenericSwapFacetV3 v2.0.0, WithdrawablePeriphery v2.0.0, LibAsset v2.2.0, LiFiDEXAggregator v1.13.0] Apr 16, 2026
…ude rules for handling errors in GenericErrors.sol
/// @dev Can only execute calldata for whitelisted function selectors
/// @custom:version 1.0.2
/// @custom:version 2.0.0
contract GenericSwapFacetV3 is ILiFi {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I chose to bump the version instead of introducing a new GenericSwapFacetV4, since the changes are purely internal. All function selectors remain unchanged, so there’s no need to maintain a legacy version of GenericSwapFacetV3.

} else {
assetId.safeTransfer(receiver, amount);
}
if (amount == 0) revert ZeroAmount();
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It’s an admin-only function, so removing it and introducing a new error won’t impact any of our offchain indexers or scripts. @0xDEnYO I’d like to double check this with you

@mirooon mirooon changed the title EXSC-241 Fix Tron USDT transfers [GenericSwapFacetV3 v2.0.0, WithdrawablePeriphery v2.0.0, LibAsset v2.2.0, LiFiDEXAggregator v1.13.0] EXSC-241 Fix Tron USDT transfers + switch to granural whitelist [GenericSwapFacetV3 v2.0.0, WithdrawablePeriphery v2.0.0, LibAsset v2.2.0, LiFiDEXAggregator v1.13.0] Apr 16, 2026
@lifi-action-bot lifi-action-bot changed the title EXSC-241 Fix Tron USDT transfers + switch to granural whitelist [GenericSwapFacetV3 v2.0.0, WithdrawablePeriphery v2.0.0, LibAsset v2.2.0, LiFiDEXAggregator v1.13.0] EXSC-241 Fix Tron USDT transfers + switch to granural whitelist [GenericSwapFacetV3 v2.0.0, PolymerCCTPFacet v2.0.0, WithdrawablePeriphery v2.0.0, LibAsset v2.2.0, LiFiDEXAggregator v1.13.0] Apr 28, 2026
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.

3 participants