Skip to content

feat: added calldata executor and bridge receiver#7

Open
tHeMaskedMan981 wants to merge 3 commits into
mainfrom
feat/dst-payload
Open

feat: added calldata executor and bridge receiver#7
tHeMaskedMan981 wants to merge 3 commits into
mainfrom
feat/dst-payload

Conversation

@tHeMaskedMan981
Copy link
Copy Markdown

@tHeMaskedMan981 tHeMaskedMan981 commented May 28, 2026

Summary by CodeRabbit

  • New Features

    • Added BungeeReceiver to execute single signed destination payloads with nonce-based replay protection
    • Added CalldataExecutor and a safe-call helper to execute external calldata with controlled return-data handling
    • Added executor interface for destination execution integration
  • Tests

    • Added end-to-end tests covering payload execution, signature/nonce checks, failure paths, and fund transfers
  • Chores

    • Added deterministic deployment and verification scripts for receiver/executor components

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 28, 2026

Caution

Review failed

Failed to post review comments

Walkthrough

Adds BungeeReceiver and CalldataExecutor plus interfaces and a safe-call library; enforces signed DestPayload execution with nonce bitmap, transfers funds, dispatches IBungeeExecutor calls via CalldataExecutor, includes CREATE3 deterministic deployment helpers/scripts and end-to-end Foundry tests.

Changes

Destination-Side Execution & Deployment

Layer / File(s) Summary
Core interfaces & safe-call utilities
src/interfaces/IBungeeExecutor.sol, src/interfaces/ICalldataExecutor.sol, src/lib/ExcessivelySafeCall.sol
IBungeeExecutor and ICalldataExecutor define execution entrypoints. ExcessivelySafeCall caps copied returndata to mitigate return-data bombs.
CalldataExecutor trusted intermediary
src/CalldataExecutor.sol
Enforces BUNGEE_RECEIVER-only executeCalldata; forwards calldata via excessivelySafeCall with MAX_COPY_BYTES = 0, returning only success boolean.
BungeeReceiver signed execution engine
src/BungeeReceiver.sol
Accepts signed DestPayload, verifies ECDSA over chain+contract-bound hash including keccak256(executionCallData), consumes nonce via assembly bitmap, transfers bridged funds to target, and dispatches IBungeeExecutor.executeData through CalldataExecutor. Includes owner-settable SOLVER_SIGNER and rescueFunds.
CREATE3 deployment & verification
scripts/deploy/create3.ts, scripts/deploy/deployReceiverAndExecutor.ts, scripts/deploy/checkReceiverDeployment.ts
Adds CREATE3 salt constants and deployment-status helpers, precomputes deterministic addresses, deploys CalldataExecutor then BungeeReceiver via CREATE3 (circular wiring), and verifies on-chain bytecode/owner when requested.
Tests & mocks
test/combined/BungeeReceiverDestPayload.t.sol
Foundry tests covering success, zero-target revert, bad signer, nonce reuse, and executor revert; includes MockERC20 and MockBungeeExecutor mocks.
Comment-only fix
src/OpenRouter.sol
Corrects Action.actionInfo bit-layout comment; no executable changes.

Sequence Diagram

sequenceDiagram
  participant Sender
  participant BungeeReceiver
  participant CalldataExecutor
  participant IBungeeExecutor
  Sender->>BungeeReceiver: executeDestPayload(payload, executionCallData, signature)
  BungeeReceiver->>BungeeReceiver: verify signature & consume nonce
  BungeeReceiver->>CalldataExecutor: executeCalldata(executor, encoded executeData, gasLimit)
  CalldataExecutor->>IBungeeExecutor: executeData(quoteId, amount, token, callData) (low-level)
  CalldataExecutor-->>BungeeReceiver: return success
  BungeeReceiver-->>Sender: emit DestPayloadExecuted(quoteId, success)
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🔐 Nonce bitmap set, a signature sings,
Funds hop to targets on tethered wings.
Calldata forwarded, safe and small,
CREATE3 builds the deterministic wall.
Tests nod — the receiver answers the call.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main feature addition: introducing CalldataExecutor and BungeeReceiver contracts for the destination-side payload execution flow.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/dst-payload

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 skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


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

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.

Actionable comments posted: 7

🤖 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 `@scripts/deploy/checkReceiverDeployment.ts`:
- Around line 69-72: The check currently only logs deployment info for
CalldataExecutor; add a strict equality check between
executorStatus.bungeeReceiver and the computed receiverAddress and, if they
differ, set hasError = true and emit a clear error/log indicating the mismatch
(include executorAddress, receiverAddress and executorStatus.bungeeReceiver for
context). Locate the block that prints the console.log for "CalldataExecutor
deployed ..." and insert the comparison and error handling there so the script
fails the check when the BUNGEE_RECEIVER wiring is not deterministic.

In `@scripts/deploy/create3.ts`:
- Around line 124-146: Update getBungeeReceiverDeploymentStatus to verify the
contract is actually a BungeeReceiver by calling one or more
BungeeReceiver-specific view methods (e.g., CALLDATA_EXECUTOR() and/or
SOLVER_SIGNER()) in addition to owner(); after confirming bytecode exists,
instantiate the Contract as you do now, call owner() and then call
CALLDATA_EXECUTOR() and/or SOLVER_SIGNER(), treat the deployment as valid only
if those Bungee-specific calls succeed and return plausible values
(addresses/non-zero), and propagate or handle errors so that exceptions from
unrelated Ownable contracts do not yield a false positive; keep the existing
return shape { address, deployed: boolean, owner?: string } and only set
deployed=true when the Bungee-specific probes succeed.

In `@scripts/deploy/deployReceiverAndExecutor.ts`:
- Around line 74-78: When executorStatus.deployed is true, assert that the
deployed executor is wired to the expected receiver by checking
executorStatus.bungeeReceiver === receiverAddress before skipping deployment; if
the check fails log an error (including executorAddress, expected
receiverAddress and actual executorStatus.bungeeReceiver) and either throw or
force redeploy. Update the branch around executorStatus.deployed (the block that
currently logs "CalldataExecutor already deployed...") to perform this
validation using executorStatus.bungeeReceiver and receiverAddress and handle
the mismatch deterministically (error/throw or redeploy) instead of silently
accepting it.

In `@src/BungeeReceiver.sol`:
- Around line 152-156: Reject zero addresses when configuring SOLVER_SIGNER and
CALLDATA_EXECUTOR: in the constructor (where SOLVER_SIGNER and CALLDATA_EXECUTOR
are assigned) add require(_solverSigner != address(0) && _calldataExecutor !=
address(0), "invalid-zero-address") so both must be non-zero, and apply the same
check to any setter/initializer that assigns these state vars (e.g., functions
that set SOLVER_SIGNER or CALLDATA_EXECUTOR such as
setSolverSigner/setCalldataExecutor or initialize) to prevent assigning
address(0).
- Around line 282-285: The unchecked subtraction of feeData.amount from
outputAmount in the POST_SWAP branch can wrap; update the block in the function
handling fee deduction (the code referencing feeData, FeeType.POST_SWAP,
CurrencyLib.transfer, and outputAmount) to first require(feeData.amount <=
outputAmount) with a clear revert/error message, then perform the transfer and
subtraction (remove or keep unchecked after the guard). This ensures any
misconfigured fee causes an immediate, explicit revert rather than a silent
wrap.

In `@src/CalldataExecutor.sol`:
- Around line 25-27: The constructor currently assigns BUNGEE_RECEIVER without
validation, allowing address(0) which would break executeCalldata access
control; update the constructor to require(_bungeeReceiver != address(0)) (or
revert with a clear error) before setting BUNGEE_RECEIVER so any zero address
passed causes deployment to revert, referencing the constructor and the
BUNGEE_RECEIVER state used by executeCalldata.
- Around line 30-36: In executeCalldata, reject EOAs/no-code targets before
calling to.excessivelySafeCall by checking to.code.length > 0 and reverting if
zero; add a guard (e.g., revert TargetNotContract() or require(to.code.length >
0, "target not contract")) immediately after the OnlyBungeeReceiver check and
before calling excessivelySafeCall so the call cannot return success for an
address with no contract code (referencing executeCalldata, BUNGEE_RECEIVER,
OnlyBungeeReceiver, excessivelySafeCall, and MAX_COPY_BYTES).
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5063be1d-6f67-4eb6-8da0-42f34351ae3e

📥 Commits

Reviewing files that changed from the base of the PR and between 2ba478e and ccca148.

📒 Files selected for processing (8)
  • scripts/deploy/checkReceiverDeployment.ts
  • scripts/deploy/create3.ts
  • scripts/deploy/deployReceiverAndExecutor.ts
  • src/BungeeReceiver.sol
  • src/CalldataExecutor.sol
  • src/interfaces/IBungeeExecutor.sol
  • src/interfaces/ICalldataExecutor.sol
  • src/lib/ExcessivelySafeCall.sol

Comment on lines +69 to +72
console.log(
`CalldataExecutor deployed on ${networkName} (chainId=${chainId}) at ${executorAddress}, BUNGEE_RECEIVER=${executorStatus.bungeeReceiver}`,
);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fail check when CalldataExecutor.BUNGEE_RECEIVER mismatches computed receiver.

This checker should enforce deterministic wiring, not just deployment presence. Add a strict comparison against receiverAddress and mark hasError = true on mismatch.

Suggested fix
   } else {
+    if (
+      !executorStatus.bungeeReceiver ||
+      executorStatus.bungeeReceiver.toLowerCase() !== receiverAddress.toLowerCase()
+    ) {
+      console.error(
+        `CalldataExecutor wiring mismatch on ${networkName} (chainId=${chainId}): expected BUNGEE_RECEIVER=${receiverAddress}, got ${executorStatus.bungeeReceiver}`,
+      );
+      hasError = true;
+    }
     console.log(
       `CalldataExecutor deployed on ${networkName} (chainId=${chainId}) at ${executorAddress}, BUNGEE_RECEIVER=${executorStatus.bungeeReceiver}`,
     );
   }

As per coding guidelines, “Check for resource leaks, race conditions, and unhandled edge cases. Flag over-engineering and premature abstractions.”

🤖 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 `@scripts/deploy/checkReceiverDeployment.ts` around lines 69 - 72, The check
currently only logs deployment info for CalldataExecutor; add a strict equality
check between executorStatus.bungeeReceiver and the computed receiverAddress
and, if they differ, set hasError = true and emit a clear error/log indicating
the mismatch (include executorAddress, receiverAddress and
executorStatus.bungeeReceiver for context). Locate the block that prints the
console.log for "CalldataExecutor deployed ..." and insert the comparison and
error handling there so the script fails the check when the BUNGEE_RECEIVER
wiring is not deterministic.

Comment thread scripts/deploy/create3.ts
Comment on lines +124 to +146
export async function getBungeeReceiverDeploymentStatus(params: {
provider: Provider;
address: string;
}): Promise<{ address: string; deployed: boolean; owner?: string }> {
const { provider, address } = params;
const bytecode = await provider.getCode(address);

if (!hasContractBytecode(bytecode)) {
return { address, deployed: false };
}

try {
const contract = new Contract(
address,
['function owner() view returns (address)'],
provider,
);
const owner = (await contract.owner()) as string;
return { address, deployed: true, owner };
} catch {
return { address, deployed: false };
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Strengthen getBungeeReceiverDeploymentStatus contract identity check.

Current logic marks deployment as valid if owner() responds. That can false-positive on unrelated Ownable contracts. This should also probe BungeeReceiver-specific view(s), e.g. CALLDATA_EXECUTOR() and/or SOLVER_SIGNER().

Suggested direction
 export async function getBungeeReceiverDeploymentStatus(params: {
   provider: Provider;
   address: string;
-}): Promise<{ address: string; deployed: boolean; owner?: string }> {
+}): Promise<{ address: string; deployed: boolean; owner?: string; calldataExecutor?: string }> {
@@
   try {
     const contract = new Contract(
       address,
-      ['function owner() view returns (address)'],
+      [
+        'function owner() view returns (address)',
+        'function CALLDATA_EXECUTOR() view returns (address)',
+      ],
       provider,
     );
     const owner = (await contract.owner()) as string;
-    return { address, deployed: true, owner };
+    const calldataExecutor = (await contract.CALLDATA_EXECUTOR()) as string;
+    return { address, deployed: true, owner, calldataExecutor };
   } catch {
     return { address, deployed: false };
   }
 }

As per coding guidelines, “Check for resource leaks, race conditions, and unhandled edge cases. Flag over-engineering and premature abstractions.”

📝 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
export async function getBungeeReceiverDeploymentStatus(params: {
provider: Provider;
address: string;
}): Promise<{ address: string; deployed: boolean; owner?: string }> {
const { provider, address } = params;
const bytecode = await provider.getCode(address);
if (!hasContractBytecode(bytecode)) {
return { address, deployed: false };
}
try {
const contract = new Contract(
address,
['function owner() view returns (address)'],
provider,
);
const owner = (await contract.owner()) as string;
return { address, deployed: true, owner };
} catch {
return { address, deployed: false };
}
}
export async function getBungeeReceiverDeploymentStatus(params: {
provider: Provider;
address: string;
}): Promise<{ address: string; deployed: boolean; owner?: string; calldataExecutor?: string }> {
const { provider, address } = params;
const bytecode = await provider.getCode(address);
if (!hasContractBytecode(bytecode)) {
return { address, deployed: false };
}
try {
const contract = new Contract(
address,
[
'function owner() view returns (address)',
'function CALLDATA_EXECUTOR() view returns (address)',
],
provider,
);
const owner = (await contract.owner()) as string;
const calldataExecutor = (await contract.CALLDATA_EXECUTOR()) as string;
return { address, deployed: true, owner, calldataExecutor };
} catch {
return { address, deployed: false };
}
}
🤖 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 `@scripts/deploy/create3.ts` around lines 124 - 146, Update
getBungeeReceiverDeploymentStatus to verify the contract is actually a
BungeeReceiver by calling one or more BungeeReceiver-specific view methods
(e.g., CALLDATA_EXECUTOR() and/or SOLVER_SIGNER()) in addition to owner(); after
confirming bytecode exists, instantiate the Contract as you do now, call owner()
and then call CALLDATA_EXECUTOR() and/or SOLVER_SIGNER(), treat the deployment
as valid only if those Bungee-specific calls succeed and return plausible values
(addresses/non-zero), and propagate or handle errors so that exceptions from
unrelated Ownable contracts do not yield a false positive; keep the existing
return shape { address, deployed: boolean, owner?: string } and only set
deployed=true when the Bungee-specific probes succeed.

Comment on lines +74 to +78
if (executorStatus.deployed) {
console.log(
`CalldataExecutor already deployed at ${executorAddress}, BUNGEE_RECEIVER=${executorStatus.bungeeReceiver}`,
);
} else {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Assert executor wiring before skipping deployment.

When executorStatus.deployed is true, this should verify executorStatus.bungeeReceiver === receiverAddress. Without that invariant, a miswired executor is silently accepted.

Suggested fix
   if (executorStatus.deployed) {
+    if (
+      !executorStatus.bungeeReceiver ||
+      executorStatus.bungeeReceiver.toLowerCase() !== receiverAddress.toLowerCase()
+    ) {
+      throw new Error(
+        `CalldataExecutor wiring mismatch: expected BUNGEE_RECEIVER=${receiverAddress}, got ${executorStatus.bungeeReceiver}`,
+      );
+    }
     console.log(
       `CalldataExecutor already deployed at ${executorAddress}, BUNGEE_RECEIVER=${executorStatus.bungeeReceiver}`,
     );
   } else {

As per coding guidelines, “Check for resource leaks, race conditions, and unhandled edge cases. Flag over-engineering and premature abstractions.”

🤖 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 `@scripts/deploy/deployReceiverAndExecutor.ts` around lines 74 - 78, When
executorStatus.deployed is true, assert that the deployed executor is wired to
the expected receiver by checking executorStatus.bungeeReceiver ===
receiverAddress before skipping deployment; if the check fails log an error
(including executorAddress, expected receiverAddress and actual
executorStatus.bungeeReceiver) and either throw or force redeploy. Update the
branch around executorStatus.deployed (the block that currently logs
"CalldataExecutor already deployed...") to perform this validation using
executorStatus.bungeeReceiver and receiverAddress and handle the mismatch
deterministically (error/throw or redeploy) instead of silently accepting it.

Comment thread src/BungeeReceiver.sol
Comment on lines +152 to +156
constructor(address _owner, address _solverSigner, address _calldataExecutor) AccessControl(_owner) {
_grantRole(RESCUE_ROLE, _owner);
SOLVER_SIGNER = _solverSigner;
CALLDATA_EXECUTOR = _calldataExecutor;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Block zero-address configuration for signer/executor.

Line 154, Line 155, and Line 170 accept zero addresses. This should be rejected to avoid accidental bricking and signer-auth ambiguity.

Suggested fix
     error InvalidSigner();
+    error InvalidAddress();
@@
     constructor(address _owner, address _solverSigner, address _calldataExecutor) AccessControl(_owner) {
+        if (_solverSigner == address(0) || _calldataExecutor == address(0)) revert InvalidAddress();
         _grantRole(RESCUE_ROLE, _owner);
         SOLVER_SIGNER = _solverSigner;
         CALLDATA_EXECUTOR = _calldataExecutor;
     }
@@
     function setSolverSigner(address _solverSigner) external onlyOwner {
+        if (_solverSigner == address(0)) revert InvalidAddress();
         SOLVER_SIGNER = _solverSigner;
         emit SolverSignerUpdated(_solverSigner);
     }

Also applies to: 169-172

🤖 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/BungeeReceiver.sol` around lines 152 - 156, Reject zero addresses when
configuring SOLVER_SIGNER and CALLDATA_EXECUTOR: in the constructor (where
SOLVER_SIGNER and CALLDATA_EXECUTOR are assigned) add require(_solverSigner !=
address(0) && _calldataExecutor != address(0), "invalid-zero-address") so both
must be non-zero, and apply the same check to any setter/initializer that
assigns these state vars (e.g., functions that set SOLVER_SIGNER or
CALLDATA_EXECUTOR such as setSolverSigner/setCalldataExecutor or initialize) to
prevent assigning address(0).

Comment thread src/BungeeReceiver.sol Outdated
Comment thread src/CalldataExecutor.sol
Comment on lines +25 to +27
constructor(address _bungeeReceiver) {
BUNGEE_RECEIVER = _bungeeReceiver;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Validate _bungeeReceiver is non-zero in constructor.

Line 26 currently allows address(0), which permanently bricks executeCalldata access control (no caller can ever be zero address). This should revert on invalid config.

Suggested fix
 contract CalldataExecutor is ICalldataExecutor {
     using ExcessivelySafeCall for address;

     error OnlyBungeeReceiver();
+    error InvalidBungeeReceiver();

@@
     constructor(address _bungeeReceiver) {
+        if (_bungeeReceiver == address(0)) revert InvalidBungeeReceiver();
         BUNGEE_RECEIVER = _bungeeReceiver;
     }
📝 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
constructor(address _bungeeReceiver) {
BUNGEE_RECEIVER = _bungeeReceiver;
}
constructor(address _bungeeReceiver) {
if (_bungeeReceiver == address(0)) revert InvalidBungeeReceiver();
BUNGEE_RECEIVER = _bungeeReceiver;
}
🤖 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/CalldataExecutor.sol` around lines 25 - 27, The constructor currently
assigns BUNGEE_RECEIVER without validation, allowing address(0) which would
break executeCalldata access control; update the constructor to
require(_bungeeReceiver != address(0)) (or revert with a clear error) before
setting BUNGEE_RECEIVER so any zero address passed causes deployment to revert,
referencing the constructor and the BUNGEE_RECEIVER state used by
executeCalldata.

Comment thread src/CalldataExecutor.sol
Comment on lines +30 to +36
function executeCalldata(address to, bytes memory encodedData, uint256 msgGasLimit) external returns (bool success) {
if (msg.sender != BUNGEE_RECEIVER) {
revert OnlyBungeeReceiver();
}

(success,) = to.excessivelySafeCall(msgGasLimit, MAX_COPY_BYTES, encodedData);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reject non-contract targets before low-level execution.

Line 35 can report success=true when to is an EOA/no-code address, which silently skips protocol execution while appearing successful. This should enforce to.code.length > 0.

Suggested fix
     error OnlyBungeeReceiver();
+    error InvalidExecutorTarget();

@@
     function executeCalldata(address to, bytes memory encodedData, uint256 msgGasLimit) external returns (bool success) {
         if (msg.sender != BUNGEE_RECEIVER) {
             revert OnlyBungeeReceiver();
         }
+        if (to.code.length == 0) revert InvalidExecutorTarget();

         (success,) = to.excessivelySafeCall(msgGasLimit, MAX_COPY_BYTES, encodedData);
     }
📝 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
function executeCalldata(address to, bytes memory encodedData, uint256 msgGasLimit) external returns (bool success) {
if (msg.sender != BUNGEE_RECEIVER) {
revert OnlyBungeeReceiver();
}
(success,) = to.excessivelySafeCall(msgGasLimit, MAX_COPY_BYTES, encodedData);
}
function executeCalldata(address to, bytes memory encodedData, uint256 msgGasLimit) external returns (bool success) {
if (msg.sender != BUNGEE_RECEIVER) {
revert OnlyBungeeReceiver();
}
if (to.code.length == 0) revert InvalidExecutorTarget();
(success,) = to.excessivelySafeCall(msgGasLimit, MAX_COPY_BYTES, encodedData);
}
🤖 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/CalldataExecutor.sol` around lines 30 - 36, In executeCalldata, reject
EOAs/no-code targets before calling to.excessivelySafeCall by checking
to.code.length > 0 and reverting if zero; add a guard (e.g., revert
TargetNotContract() or require(to.code.length > 0, "target not contract"))
immediately after the OnlyBungeeReceiver check and before calling
excessivelySafeCall so the call cannot return success for an address with no
contract code (referencing executeCalldata, BUNGEE_RECEIVER, OnlyBungeeReceiver,
excessivelySafeCall, and MAX_COPY_BYTES).

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