Skip to content

fix(contracts): bridge approval safety + IRYLA interface decoupling#24

Merged
iap merged 3 commits into
devfrom
feat/bridge-approval-fix-iryla-interface
May 6, 2026
Merged

fix(contracts): bridge approval safety + IRYLA interface decoupling#24
iap merged 3 commits into
devfrom
feat/bridge-approval-fix-iryla-interface

Conversation

@iap
Copy link
Copy Markdown
Contributor

@iap iap commented May 6, 2026

Summary

Two targeted contract improvements identified during code review.

Changes

fix(bridge): clear approval and revert cleanly on sendERC20 failure

  • Wraps sendERC20 in try/catch in MARKBridgeAdapter.bridgeTo
  • On revert: forceApprove(0) clears dangling approval, BridgeFailed() raised
  • Prevents tokens being stuck in adapter with open approval if bridge call fails
  • Adds BridgeFailed error to BridgeErrors

refactor(settlement): decouple from RYLA concrete type via IRYLA interface

  • Extracts IRYLA interface (mint, burn, balanceOf) into src/interfaces/
  • MARKSettlementModule now imports IRYLA instead of concrete RYLA
  • Reduces coupling between settlement and token domains

Scope

  • contracts

Verification

  • forge build — clean
  • forge test — 58/58 pass

Risk

Low — no logic changes to settlement flow, bridge fix only adds safety on the failure path.

Summary by CodeRabbit

  • Bug Fixes

    • Bridge calls now handle failures safely: operations revert on bridge send failure and reset token approvals.
  • Refactor

    • Settlement logic switched to interface-based token interactions for greater modularity.
  • New

    • Added a lightweight token interface exposing mint, burn and balance checks.
  • Tests

    • Added a test that verifies bridge failure reverts and clears token approval.

iap added 2 commits May 6, 2026 22:43
Wrap sendERC20 in try/catch — on revert, forceApprove(0) clears the
dangling approval and BridgeFailed() is raised. Prevents tokens from
being stuck in the adapter with an open approval if the bridge call
fails.
…rface

Extract IRYLA interface (mint, burn, balanceOf) into src/interfaces/.
MARKSettlementModule now depends on the interface rather than the
concrete RYLA implementation, reducing coupling between domains.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 6, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 6d3f433c-2b79-49a4-adf3-5d4db54898c0

📥 Commits

Reviewing files that changed from the base of the PR and between 20f7e35 and 16537b2.

📒 Files selected for processing (3)
  • contracts/src/interfaces/IRYLA.sol
  • contracts/src/settlement/MARKSettlementModule.sol
  • contracts/test/unit/bridge/MARKBridgeAdapter.t.sol

Walkthrough

A try/catch wrapper is added around the Superchain bridge ERC20 send in MARKBridgeAdapter; on failure it resets token approval and reverts with a new BridgeFailed error. An IRYLA interface is introduced and MARKSettlementModule now depends on IRYLA instead of concrete RYLA.

Changes

Bridge Error Handling and Settlement Abstraction

Layer / File(s) Summary
Interface Definition
contracts/src/interfaces/IRYLA.sol
Adds IRYLA interface with mint(address,uint256), burn(uint256), and balanceOf(address) external view returns (uint256).
Error Definition
contracts/src/errors/BridgeErrors.sol
Adds new BridgeFailed() error declaration.
Core Error Handling
contracts/src/bridge/MARKBridgeAdapter.sol
Replaces direct bridge call with try/catch around sendERC20; on success stores returned message hash, on failure resets approval to zero and reverts with BridgeFailed.
Settlement Wiring
contracts/src/settlement/MARKSettlementModule.sol
Replaces concrete RYLA usage with IRYLA type: import, immutable TOKEN type, constructor initialization, and token transfer/burn call sites updated accordingly.
Tests
contracts/test/unit/bridge/MARKBridgeAdapter.t.sol
Adds test testBridgeToRevertsWithBridgeFailedAndClearsApprovalOnSendERC20Revert() which mocks sendERC20 revert, expects BridgeFailed, and asserts approval reset to 0.

Sequence Diagram

sequenceDiagram
    participant Adapter as MARKBridgeAdapter
    participant Bridge as Superchain Bridge
    participant Token as ERC20 Token

    Adapter->>Token: approve(Bridge, amount)
    Adapter->>Bridge: sendERC20(token, to, amount)
    alt Bridge success
        Bridge->>Token: transferFrom(Adapter, recipient, amount)
        Bridge-->>Adapter: returns messageHash
        Adapter->>Adapter: store messageHash
    else Bridge revert
        Bridge-->>Adapter: throws
        Adapter->>Token: approve(Bridge, 0) rgba(255,0,0,0.5)
        Adapter-->>Adapter: revert BridgeFailed()
    end
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰
A bridge that hops but sometimes slips,
I catch the fall and tidy drips.
Approvals cleared when winds blow hard,
IRYLA waits without discard.
Tiny paws, a careful guard.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the two main changes: bridge approval safety fix and IRYLA interface decoupling.
Description check ✅ Passed The description provides a clear summary of changes with verification results, but is missing several required template sections like Risk Review checklist items.
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 feat/bridge-approval-fix-iryla-interface

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

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 6, 2026

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

Copy link
Copy Markdown

@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 (2)
contracts/src/bridge/MARKBridgeAdapter.sol (1)

95-102: ⚡ Quick win

Add a unit test for the new catch branch in bridgeTo.

The failure path is newly introduced, but current test context only demonstrates success flow. Please add a test that mocks sendERC20 revert and asserts BridgeFailed() is raised.

🤖 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 `@contracts/src/bridge/MARKBridgeAdapter.sol` around lines 95 - 102, Add a unit
test for the failure path of bridgeTo that stubs/mocks
SUPERCHAIN_TOKEN_BRIDGE.sendERC20 to revert, then calls the contract's bridgeTo
entry (the function containing the try/catch around
SUPERCHAIN_TOKEN_BRIDGE.sendERC20) and asserts the call reverts with
BridgeFailed(); additionally verify that TOKEN.forceApprove was invoked with 0
and that no messageHash is returned/updated after the revert. Use the sendERC20,
SUPERCHAIN_TOKEN_BRIDGE, TOKEN.forceApprove, BridgeFailed, and the bridgeTo
function names to locate and hook the behavior in your test harness/mocks.
contracts/src/interfaces/IRYLA.sol (1)

6-10: ⚡ Quick win

Make IRYLA explicitly inherit IERC20 to match downstream usage.

MARKSettlementModule casts TOKEN (typed as IRYLA) to IERC20 when calling safeTransferFrom(). Declaring IRYLA is IERC20 makes this dependency explicit, eliminates the unsafe type cast, and provides type-safety guarantees for future implementations.

♻️ Proposed refactor
 // SPDX-License-Identifier: MIT
 pragma solidity ^0.8.25;

+import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
+
 /// `@title` IRYLA
 /// `@notice` Minimal interface for settlement modules interacting with the RYLA token.
-interface IRYLA {
+interface IRYLA is IERC20 {
     function mint(address to, uint256 amount) external;
     function burn(uint256 amount) external;
-    function balanceOf(address account) external view returns (uint256);
 }
🤖 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 `@contracts/src/interfaces/IRYLA.sol` around lines 6 - 10, Update the IRYLA
interface to explicitly inherit IERC20 (change `interface IRYLA {` to `interface
IRYLA is IERC20 {`) and add the required import for IERC20 so the compiler
recognizes it; keep the existing mint, burn, and balanceOf signatures and ensure
they don't conflict with IERC20. This makes downstream usage in
MARKSettlementModule (where `TOKEN` typed as `IRYLA` is cast to IERC20 for
`safeTransferFrom`) type-safe and removes the need for unsafe casting.
🤖 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 `@contracts/src/bridge/MARKBridgeAdapter.sol`:
- Around line 95-102: Add a unit test for the failure path of bridgeTo that
stubs/mocks SUPERCHAIN_TOKEN_BRIDGE.sendERC20 to revert, then calls the
contract's bridgeTo entry (the function containing the try/catch around
SUPERCHAIN_TOKEN_BRIDGE.sendERC20) and asserts the call reverts with
BridgeFailed(); additionally verify that TOKEN.forceApprove was invoked with 0
and that no messageHash is returned/updated after the revert. Use the sendERC20,
SUPERCHAIN_TOKEN_BRIDGE, TOKEN.forceApprove, BridgeFailed, and the bridgeTo
function names to locate and hook the behavior in your test harness/mocks.

In `@contracts/src/interfaces/IRYLA.sol`:
- Around line 6-10: Update the IRYLA interface to explicitly inherit IERC20
(change `interface IRYLA {` to `interface IRYLA is IERC20 {`) and add the
required import for IERC20 so the compiler recognizes it; keep the existing
mint, burn, and balanceOf signatures and ensure they don't conflict with IERC20.
This makes downstream usage in MARKSettlementModule (where `TOKEN` typed as
`IRYLA` is cast to IERC20 for `safeTransferFrom`) type-safe and removes the need
for unsafe casting.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 846ac536-85cd-446b-9352-6cabebf858a7

📥 Commits

Reviewing files that changed from the base of the PR and between 0573b9b and 20f7e35.

📒 Files selected for processing (4)
  • contracts/src/bridge/MARKBridgeAdapter.sol
  • contracts/src/errors/BridgeErrors.sol
  • contracts/src/interfaces/IRYLA.sol
  • contracts/src/settlement/MARKSettlementModule.sol

…test

- IRYLA now inherits IERC20, eliminating the unsafe cast in
  MARKSettlementModule (using SafeERC20 for IRYLA directly)
- Remove unused IERC20 import from MARKSettlementModule
- Add unit test for BridgeFailed catch branch: mocks sendERC20 revert,
  asserts BridgeFailed() raised and approval reset to 0
@iap iap merged commit 51c8f1c into dev May 6, 2026
19 checks passed
@iap iap deleted the feat/bridge-approval-fix-iryla-interface branch May 6, 2026 16:41
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.

1 participant