Skip to content

feat(FraxFacet): add Frax HopV2 (LayerZero OFT) bridge facet (EXSC-382) [FraxFacet v1.0.0, IFraxHopV2 v1.0.0]#2048

Draft
0xDEnYO wants to merge 5 commits into
mainfrom
feature/exsc-382-frax-sc-implementation
Draft

feat(FraxFacet): add Frax HopV2 (LayerZero OFT) bridge facet (EXSC-382) [FraxFacet v1.0.0, IFraxHopV2 v1.0.0]#2048
0xDEnYO wants to merge 5 commits into
mainfrom
feature/exsc-382-frax-sc-implementation

Conversation

@0xDEnYO

@0xDEnYO 0xDEnYO commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Which Linear task belongs to this PR?

EXSC-382 (sub-task EXSC-383) — Frax bridge SC implementation.

Why did I implement it this way?

FraxFacet bridges through Frax HopV2, a LayerZero V2 OFT hub-and-spoke bridge (Fraxtal chainId 252 is the hub; every other chain is a spoke sharing one CREATE2 address). It calls HopV2.sendOFT(oft, dstEid, recipient, amountLd, 0, "") for the six Frax OFTs (frxUSD, sfrxUSD, WFRAX, frxETH, sfrxETH, FPI).

One facet source for every chain, incl. Tempo. Tempo's LayerZero EndpointV2Alt rejects native msg.value and charges the messaging fee in a TIP20 ERC20 gas token. Rather than a second contract, the fee mode is selected by a constructor immutable (TIP_FEE_MANAGER, non-zero only on Tempo, with PATH_USD as the default gas token) read from config/frax.json at deploy time. This keeps one @custom:version, one audit surface, and one Deploy script; the standard-chain runtime cost is an immutable read + one branch (≈ free), the only price being a few-k gas of one-time deploy bloat for the unused branch on 26 chains.

Money flow (the crux of the review):

  • Excess native fee — the LI.FI/Frax API quotes the native fee with a ~10% buffer; HopV2 refunds the excess to the caller (the diamond) synchronously, and the facet forwards it to refundRecipient via refundExcessNative. This is a hot path, not an edge case.
  • Dust — HopV2 floors the amount to the OFT's decimalConversionRate multiple and only pulls the floored amount. The facet floors up front, bridges exactly that, returns the dust remainder to refundRecipient in-tx, and emits LiFiTransferStarted.minAmount = the bridged (floored) amount. The diamond retains zero token and zero native after every bridge (asserted in tests).
  • No positive slippage / no intent semanticsminAmountLD == amountLD; destination funds go straight to the recipient. No LI.FI contract ever holds funds on the destination.
  • Tempomsg.value == 0; the fee token is resolved (TIP_FEE_MANAGER.userTokens(diamond)PATH_USD), pulled from the caller, approved to the hop, and any unpulled remainder is swept back to refundRecipient (invariant holds even across a HopV2 proxy upgrade).

Plain transfers only. hasDestinationCall == true reverts (doesNotContainDestinationCalls); no receiver periphery, and CalldataVerificationFacet is unchanged (no compose message to validate on-chain — same as PaxosTransitFacet).

Trust assumptions (documented in docs/FraxFacet.md):

  • dstEid is trusted from backend-generated calldata; bridgeData.destinationChainId (analytics-only) is not cross-checked against it — same model as AcrossFacetV4/PaxosTransitFacet. An unsupported dstEid routes funds through Fraxtal where they can be stranded pending Frax-admin recovery.
  • HopV2 is an upgradeable proxy with an admin recover(); the facet grants it the standard maxApproveERC20 allowance.

⚠️ Open item for BE / SC review — Tempo fee funding (EXP-514). On Tempo the diamond must possess the TIP20 fee token for the hop's transferFrom pull; the facet pulls it from the caller via depositAsset, so the caller must make the fee token available to the diamond. This is my best reversible inference from the verified RemoteHopV2Tempo source and needs BE confirmation — it does not change the facet ABI, so it can be adjusted without a redesign.

Testing: test/solidity/Facets/FraxFacet.t.sol — 36 tests, 100% line/statement/function coverage on FraxFacet.sol. Standard path uses an Arbitrum mainnet fork against the real HopV2 + frxUSD self-OFT with live fee quoting; the Tempo path uses MockFraxHopV2Tempo (rule 400: Tempo's TIP20/endpoint are precompile-backed and cannot be forked). Facet compiles clean under the deploy toolchain (solc 0.8.17 + london).

Follow-ups (out of scope here): SC peer review → BE integration (EXP-514) → external audit → staging then production rollout (multisig + diamondCut + diamond-log update). Aurora is excluded (absent from config/networks.json; needs /add-network) — tracked separately.

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
  • I have added tests that cover the functionality / test the bug
  • For new facets: I have checked all points from this list: https://www.notion.so/lifi/New-Facet-Contract-Checklist-157f0ff14ac78095a2b8f999d655622e
  • I have updated any required documentation

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>

0xDEnYO and others added 4 commits July 13, 2026 13:28
… + deploy scripts (EXSC-382)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…+ clearSigning (EXSC-382)

- swap entrypoint: reject stray msg.value on Tempo; require final swap output == sendingAssetId
- Tempo: return unpulled fee-token remainder to refundRecipient (invariant holds across hop upgrades)
- docs/FraxFacet.md; regenerate clearSigningProposal.json (both Frax entrypoints)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…C20-fee path (EXSC-382)

- 29 Arbitrum-fork tests (real HopV2 + frxUSD self-OFT): dust floor+refund, excess-native refund,
  diamond-retains-nothing, oft/token mismatch, validation reverts, swap-output guard
- 7 local Tempo tests via MockFraxHopV2Tempo (precompile TIP20 can't fork; rule 400): msg.value==0
  guard, ERC20 fee pull, opted-in fee token, unused-fee sweep

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…o guard wording in docs (EXSC-382)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@lifi-action-bot lifi-action-bot marked this pull request as draft July 13, 2026 07:36
@github-actions github-actions Bot added the requires-types Trigger Types Bindings CI (ABI/type generation for lifi-contract-types) label Jul 13, 2026
@lifi-action-bot lifi-action-bot changed the title feat(FraxFacet): add Frax HopV2 (LayerZero OFT) bridge facet (EXSC-382) feat(FraxFacet): add Frax HopV2 (LayerZero OFT) bridge facet (EXSC-382) [FraxFacet v1.0.0, IFraxHopV2 v1.0.0] Jul 13, 2026
Comment thread src/Facets/FraxFacet.sol
/// @dev Contains the business logic for bridging via Frax HopV2
/// @param _bridgeData The core information needed for bridging
/// @param _fraxData Data specific to Frax HopV2
function _startBridge(
Comment thread src/Facets/FraxFacet.sol
flooredAmount
);

bytes32 recipient = bytes32(uint256(uint160(_bridgeData.receiver)));
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 67d85f31-1339-4f86-81e0-2dc4a166b948

📥 Commits

Reviewing files that changed from the base of the PR and between 42bfa17 and 0c28eda.

📒 Files selected for processing (2)
  • docs/FraxFacet.md
  • script/demoScripts/demoFrax.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • docs/FraxFacet.md
  • script/demoScripts/demoFrax.ts

Walkthrough

Changes

Frax bridging integration

Layer / File(s) Summary
FraxFacet bridge contract
src/Facets/FraxFacet.sol, src/Interfaces/IFraxHopV2.sol
Adds Frax HopV2 interfaces and standard or Tempo bridging entrypoints with dust handling, refunds, validation, and swap support.
Configuration and deployment wiring
config/frax.json, script/deploy/..., script/deploy/resources/deployRequirements.json
Adds chain-specific Frax addresses and deployment/update scripts for standard and zkSync environments.
Bridge and Tempo test coverage
test/solidity/Facets/FraxFacet.t.sol
Tests fork-based bridging, swaps, validation failures, dust and native refunds, constructor checks, and Tempo ERC20 fee handling.
Tempo mock environment
test/solidity/utils/MockFraxHopV2Tempo.sol
Adds mock OFT, fee manager, ERC20 behavior, HopV2 fee quoting, dust flooring, and token transfers.
Demo, signing metadata, and documentation
script/demoScripts/demoFrax.ts, config/clearSigningProposal.json, docs/FraxFacet.md
Adds a staging Frax bridge demo, signing definitions for both entrypoints, and documentation with route, fee, validation, and quote examples.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly names the FraxFacet HopV2 bridge facet and the related task, matching the main change set.
Description check ✅ Passed The description follows the template with task, rationale, and review checklists, though a few checklist items remain unchecked.
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.
✨ 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 feature/exsc-382-frax-sc-implementation

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


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.

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
src/Interfaces/IFraxHopV2.sol (1)

72-92: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Move the auxiliary interfaces into dedicated files.

Place ITipFeeManager and IFraxOFT in src/Interfaces/ITipFeeManager.sol and src/Interfaces/IFraxOFT.sol, respectively.

As per coding guidelines, “Solidity interfaces should be placed in separate files with the I prefix naming convention.”

🤖 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 `@src/Interfaces/IFraxHopV2.sol` around lines 72 - 92, The auxiliary interfaces
ITipFeeManager and IFraxOFT should not remain in IFraxHopV2.sol. Move each
interface into its own dedicated file, src/Interfaces/ITipFeeManager.sol and
src/Interfaces/IFraxOFT.sol, preserving their declarations and documentation,
and update any imports or references to use the new locations.

Source: Coding guidelines

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

Inline comments:
In `@config/clearSigningProposal.json`:
- Around line 806-872: Update both Frax clear-signing entries to display
_fraxData.dstEid as the destination and _fraxData.refundRecipient as the refund
recipient, replacing the descriptive _bridgeData.destinationChainId presentation
where appropriate. Add visible field definitions for both _fraxData paths in
each entry, using suitable destination and address formatting while preserving
the existing bridge fields.

In `@docs/FraxFacet.md`:
- Around line 127-134: Update the “LiFi Data” documentation to clarify that
BridgeData is not strictly for analytics: explain that fields such as
sendingAssetId, receiver, and minAmount affect transfer behavior, while limiting
the analytics description to metadata such as transaction ID, integrator, and
referrer.

In `@script/demoScripts/demoFrax.ts`:
- Around line 243-283: Replace the warning-only sanity checks in the quote
mapping flow with validation that aborts before sending funds when any external
quote field mismatches expectations: oft, dstEid, recipient, amountLd,
approvalAddress, or transactionRequest.to. Derive the expected Hop target as
FRAX_HOP_SPOKE for both routes because Arbitrum is always the source, and
compare addresses and numeric values using appropriate normalized
representations. Preserve the existing API-derived values only after all
validations pass.

In `@src/Facets/FraxFacet.sol`:
- Line 229: Update the Tempo fee refund logic surrounding _sendViaTempo in
FraxFacet so the refund baseline accounts for the bridged token when feeToken
equals _bridgeData.sendingAssetId. Exclude _amount from the pre-snapshot or
otherwise track only the fee-funded deposit, preventing balanceOf(address(this))
- feeTokenBalanceBefore from underflowing after sendOFT transfers the bridged
tokens.

---

Nitpick comments:
In `@src/Interfaces/IFraxHopV2.sol`:
- Around line 72-92: The auxiliary interfaces ITipFeeManager and IFraxOFT should
not remain in IFraxHopV2.sol. Move each interface into its own dedicated file,
src/Interfaces/ITipFeeManager.sol and src/Interfaces/IFraxOFT.sol, preserving
their declarations and documentation, and update any imports or references to
use the new locations.
🪄 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: 93c6ffc8-add5-49b0-9067-b1b2bb107c25

📥 Commits

Reviewing files that changed from the base of the PR and between 6949564 and 42bfa17.

📒 Files selected for processing (13)
  • config/clearSigningProposal.json
  • config/frax.json
  • docs/FraxFacet.md
  • script/demoScripts/demoFrax.ts
  • script/deploy/facets/DeployFraxFacet.s.sol
  • script/deploy/facets/UpdateFraxFacet.s.sol
  • script/deploy/resources/deployRequirements.json
  • script/deploy/zksync/DeployFraxFacet.zksync.s.sol
  • script/deploy/zksync/UpdateFraxFacet.zksync.s.sol
  • src/Facets/FraxFacet.sol
  • src/Interfaces/IFraxHopV2.sol
  • test/solidity/Facets/FraxFacet.t.sol
  • test/solidity/utils/MockFraxHopV2Tempo.sol

Comment on lines +806 to +872
"startBridgeTokensViaFrax((bytes32 transactionId, string bridge, string integrator, address referrer, address sendingAssetId, address receiver, uint256 minAmount, uint256 destinationChainId, bool hasSourceSwaps, bool hasDestinationCall) _bridgeData, (address oft, uint32 dstEid, uint256 nativeFee, address refundRecipient) _fraxData)": {
"intent": "Bridge via Frax",
"interpolatedIntent": "Bridge {_bridgeData.minAmount} via Frax to chain {_bridgeData.destinationChainId} for {_bridgeData.receiver}",
"fields": [
{
"path": "_bridgeData.minAmount",
"label": "Amount to Bridge",
"format": "tokenAmount",
"params": {
"tokenPath": "_bridgeData.sendingAssetId"
},
"visible": "always"
},
{
"path": "_bridgeData.destinationChainId",
"label": "Destination Chain",
"format": "raw",
"visible": "always"
},
{
"path": "_bridgeData.receiver",
"label": "Recipient",
"format": "addressName",
"params": {
"types": [
"eoa",
"contract"
],
"sources": [
"local",
"ens"
]
},
"visible": "always"
},
{
"path": "_bridgeData.transactionId",
"label": "Transaction Id",
"visible": "never"
},
{
"path": "_bridgeData.bridge",
"label": "Bridge",
"visible": "never"
},
{
"path": "_bridgeData.integrator",
"label": "Integrator",
"visible": "never"
},
{
"path": "_bridgeData.referrer",
"label": "Referrer",
"visible": "never"
},
{
"path": "_bridgeData.hasSourceSwaps",
"label": "Has Source Swaps",
"visible": "never"
},
{
"path": "_bridgeData.hasDestinationCall",
"label": "Has Destination Call",
"visible": "never"
}
]
},

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.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the reviewed config entry and related source/generator definitions.
git ls-files | rg '^config/clearSigningProposal\.json$|Frax|clearSigningProposal|signing proposal|clear signing' || true

echo '--- search for Frax-related clear signing definitions ---'
rg -n '"startBridgeTokensViaFrax|dstEid|refundRecipient|clearSigningProposal|Frax"' config src script .cursor -g '!**/dist/**' -g '!**/build/**' || true

echo '--- locate the reviewed block in config/clearSigningProposal.json ---'
rg -n -A40 -B20 '"startBridgeTokensViaFrax\(\(bytes32 transactionId, string bridge, string integrator, address referrer, address sendingAssetId, address receiver, uint256 minAmount, uint256 destinationChainId, bool hasSourceSwaps, bool hasDestinationCall\) _bridgeData, \(address oft, uint32 dstEid, uint256 nativeFee, address refundRecipient\) _fraxData\)"' config/clearSigningProposal.json || true

echo '--- find the generator/source that emits these descriptors ---'
fd -a 'clearSigningProposal*' . || true
fd -a '*signing*proposal*' . || true
fd -a '*Frax*' src script config . || true

Repository: lifinance/contracts

Length of output: 18151


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- FraxFacet relevant slice ---'
cat -n src/Facets/FraxFacet.sol | sed -n '1,380p'

echo '--- search for clearSigningProposal generator/templates ---'
rg -n "clearSigningProposal|clear signing|signing proposal|proposal" .cursor src script config docs -g '!**/dist/**' -g '!**/build/**' || true

echo '--- list likely generator files with correct globs ---'
fd -a --glob '*clear*sign*' . || true
fd -a --glob '*proposal*' . || true
fd -a --glob '*signing*' . || true

Repository: lifinance/contracts

Length of output: 50375


Display _fraxData.dstEid and _fraxData.refundRecipient in both Frax clear-signing entries.
_bridgeData.destinationChainId is only descriptive here; the facet actually bridges with _fraxData.dstEid, and _fraxData.refundRecipient receives dust and any refunded native/fee leftovers. Surface those fields in both Frax entries so the signing UI reflects the real destination and recipient.

🤖 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 `@config/clearSigningProposal.json` around lines 806 - 872, Update both Frax
clear-signing entries to display _fraxData.dstEid as the destination and
_fraxData.refundRecipient as the refund recipient, replacing the descriptive
_bridgeData.destinationChainId presentation where appropriate. Add visible field
definitions for both _fraxData paths in each entry, using suitable destination
and address formatting while preserving the existing bridge fields.

Comment thread docs/FraxFacet.md Outdated
Comment thread script/demoScripts/demoFrax.ts
Comment thread src/Facets/FraxFacet.sol
""
);
} else {
_sendViaTempo(_fraxData, recipient, flooredAmount);

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

ast-grep outline src/Facets/FraxFacet.sol --view expanded
rg -n "_sendViaTempo|feeTokenBalanceBefore|sendOFT|feeToken" src/Facets/FraxFacet.sol src -g '*.sol'
sed -n '200,340p' src/Facets/FraxFacet.sol

Repository: lifinance/contracts

Length of output: 6887


🏁 Script executed:

ast-grep outline src/Interfaces/IFraxHopV2.sol --view expanded
sed -n '1,220p' src/Interfaces/IFraxHopV2.sol
rg -n "TIP_FEE_MANAGER|userTokens|quoteStatic|sendOFT|fee token|Tempo" docs src -g '*.sol' -g '*.md'

Repository: lifinance/contracts

Length of output: 9436


🏁 Script executed:

sed -n '1,220p' src/Interfaces/IFraxHopV2.sol
rg -n "TIP_FEE_MANAGER|userTokens|quoteStatic|sendOFT|fee token|Tempo" docs src -g '*.sol' -g '*.md'

Repository: lifinance/contracts

Length of output: 9392


Handle the bridged token in the Tempo fee refund path.

If feeToken == _bridgeData.sendingAssetId, the pre-snapshot already includes _amount, so balanceOf(address(this)) - feeTokenBalanceBefore underflows after sendOFT pulls the bridged tokens. Exclude the bridged amount from the refund baseline or track the fee-only deposit separately.

🤖 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 `@src/Facets/FraxFacet.sol` at line 229, Update the Tempo fee refund logic
surrounding _sendViaTempo in FraxFacet so the refund baseline accounts for the
bridged token when feeToken equals _bridgeData.sendingAssetId. Exclude _amount
from the pre-snapshot or otherwise track only the fee-funded deposit, preventing
balanceOf(address(this)) - feeTokenBalanceBefore from underflowing after sendOFT
transfers the bridged tokens.

@lifi-action-bot

Copy link
Copy Markdown
Collaborator

Test Coverage Report

Line Coverage: 90.26% (3485 / 3861 lines)
Function Coverage: 93.84% ( 534 / 569 functions)
Branch Coverage: 73.38% ( 648 / 883 branches)
Test coverage (90.26%) is above min threshold (89%). Check passed.

…ing mismatch; docs clarify enforced BridgeData fields (EXSC-382)

- demoFrax: source-chain Hop is always the arbitrum spoke for both routes; validate oft/dstEid/recipient/amount/approvalAddress/to and throw on mismatch instead of warn
- docs: BridgeData is not strictly analytics — sendingAssetId/receiver/minAmount are enforced

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@0xDEnYO

0xDEnYO commented Jul 13, 2026

Copy link
Copy Markdown
Contributor Author

Bot-review triage

Applied (pushed):

  • CodeRabbit — demoFrax.ts routing: fixed. The source-chain Hop is always the arbitrum spoke for both routes (arbitrum is the source), and the demo now validates oft/dstEid/recipient/amount/approvalAddress/transactionRequest.to and throws on mismatch instead of warning.
  • CodeRabbit — docs "BridgeData is strictly analytics": fixed. Clarified that sendingAssetId/receiver/minAmount are enforced; only transactionId/integrator/referrer/destinationChainId are descriptive.

Rejected (with reason):

  • CodeRabbit — show _fraxData.dstEid/refundRecipient in the clear-signing entries: config/clearSigningProposal.json is generated by tasks/buildClearSigningProposal.ts, which emits only the standard _bridgeData/_swapData descriptors — no facet displays facet-specific struct fields. A manual edit would be inconsistent with every other facet, get overwritten on regeneration, and fail the verify-clear-signing CI that asserts committed == generated. The clear-signing surface is intentionally generator-driven.
  • Olympix — "reentrancy: event emitted after external call" (FraxFacet.sol, LiFiTransferStarted): intentional and mandated by [CONV:EVENTS] (emit at the end of _startBridge after the bridge call), and the entrypoints are nonReentrant. Same pattern as every LI.FI facet.
  • Olympix — "unsafe downcast": false positive. The flagged expression is bytes32(uint256(uint160(receiver))) — all widening; there is no narrowing cast in the facet.

Note: audit-verification failing + the auto-draft / AuditRequired label are the expected new-facet gate; the external audit is a downstream step (SC review → BE → audit → prod rollout).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AuditRequired requires-types Trigger Types Bindings CI (ABI/type generation for lifi-contract-types)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants