Skip to content

Commit

Permalink
feat(contracts/solve): drastically optimized SolverNet orderData (#2954)
Browse files Browse the repository at this point in the history
By completely refactoring the `OrderData` type and storing it instead of
a `ResolvedCrossChainOrder` type, I managed to reduce costs by ~70%. The
new type requires 6 slots minimally, with 2 additional slots per token
approval required. This is substantially optimized from the 25+ slots
required to store the entire ERC7683 resolved order.

The user and solver-facing interface remains completely unchanged. The
only breaking change in this implementation is that the `OrderData` is
much different. However, it is also flatter, which should make it easier
for the solver to populate.

issue: #2917
  • Loading branch information
Zodomo authored Feb 3, 2025
1 parent 5c0fe6f commit 2722d1b
Show file tree
Hide file tree
Showing 7 changed files with 1,192 additions and 0 deletions.
74 changes: 74 additions & 0 deletions contracts/solve/src/_optimized/SolverNetExecutor.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity =0.8.24;

import { SafeTransferLib } from "solady/src/utils/SafeTransferLib.sol";
import { ISolverNetExecutor } from "./interfaces/ISolverNetExecutor.sol";
import { AddrUtils } from "../lib/AddrUtils.sol";

contract SolverNetExecutor is ISolverNetExecutor {
using SafeTransferLib for address;
using AddrUtils for bytes32;

/**
* @notice Address of the outbox.
*/
address public immutable outbox;

/**
* @notice Modifier to provide access control to the outbox.
* @dev This was used as it is more efficient than using Ownable. Only the outbox will call these functions.
*/
modifier onlyOutbox() {
if (msg.sender != outbox) revert NotOutbox();
_;
}

constructor(address _outbox) {
outbox = _outbox;
}

/**
* @notice Approves a spender (usually call target) to spend a token held by the executor.
* @dev Called prior to `execute` in order to ensure tokens can be spent and after to purge excess approvals.
*/
function approve(address token, address spender, uint256 amount) external onlyOutbox {
token.safeApprove(spender, amount);
}

/**
* @notice Executes a call.
* @param target Address of the contract to call.
* @param value Value to send with the call.
* @param data Data to send with the call.
*/
function execute(address target, uint256 value, bytes calldata data) external payable onlyOutbox {
(bool success,) = payable(target).call{ value: value }(data);
if (!success) revert CallFailed();
}

/**
* @notice Transfers a token to a recipient.
* @dev Called after `execute` in order to refund any excess or returned tokens.
*/
function transfer(address token, address to, uint256 amount) external onlyOutbox {
token.safeTransfer(to, amount);
}

/**
* @notice Transfers native currency to a recipient.
* @dev Called after `execute` in order to refund any native currency sent back to the executor.
*/
function transferNative(address to, uint256 amount) external onlyOutbox {
to.safeTransferETH(amount);
}

/**
* @dev Allows target contracts to arbitrarily return native tokens to the executor.
*/
receive() external payable { }

/**
* @dev Allows target contracts to arbitrarily return native tokens to the executor.
*/
fallback() external payable { }
}
Loading

0 comments on commit 2722d1b

Please sign in to comment.