# Solver Call Data

#### What is `solverOpData`?

The `solverOpData` parameter is a crucial component that contains the **transaction data** required by your **solver contract**. This data ensures that your MEV strategy executes precisely and securely within the Atlas ecosystem.

#### **Why is `solverOpData` Important?**

* **Executes** your MEV strategy on the solver contract
* Atlas constructs the call to `atlasSolverCall` and passes the `solverOpData` along.

The simplest way to obtain the correct `solverOpData` is to create a transaction directly to your solver contract (as if Atlas didn't exist) and extract that transaction's `data` field.

There are two primary approaches to using `solverOpData`, and the choice depends on your specific implementation:

1. [**Directly Implementing MEV Logic in Your Solver Contract**](#approach-1-direct-mev-logic-implementation-in-solver-contract)
2. [**Proxying Calls to an External Searcher Contract**](#approach-2-proxying-calls-to-an-external-contract)

***

There are many approaches on how you want to use the `solverOpData` and they're ultimately up to you.

## Potential Approaches:

## **Approach 1: Direct  MEV Logic Implementation in Solver Contract**

MEV logic alongside the solver contract which implements the [`ISolverContract`](https://github.com/FastLane-Labs/atlas/blob/main/src/contracts/interfaces/ISolverContract.sol)

* `atlasSolverCall` should be calling an internal function\
  In this method, your solver contract contains all the MEV logic within its functions. The `solverOpData` is an encoding of a function call within your solver contract, such as `solve()`

We provide a helper [`SolverBase`](https://github.com/FastLane-Labs/atlas/blob/main/src/contracts/solver/SolverBase.sol) which redirects the callData. Your `solverOpData` should encode your function here `solve`()

```solidity
// SolverBase.sol
 ...
function atlasSolverCall(
        address solverOpFrom,
        address executionEnvironment,
        address bidToken,
        uint256 bidAmount,
        bytes calldata solverOpData,
        bytes calldata
    )
        external
        payable
        virtual
        safetyFirst(executionEnvironment, solverOpFrom)
        payBids(executionEnvironment, bidToken, bidAmount)
    {
        (bool success,) = address(this).call{ value: msg.value }(solverOpData);
        if (!success) revert SolverCallUnsuccessful();
    }
```

Example Contract AtlasDirectSolver

<pre class="language-solidity"><code class="lang-solidity"><strong>// SPDX-License-Identifier: MIT
</strong>
pragma solidity 0.8.25;

import { SafeTransferLib } from "solady/utils/SafeTransferLib.sol";
import { Ownable } from "openzeppelin-contracts/contracts/access/Ownable.sol";
import { IERC20 } from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import { SolverBase } from "../lib/atlas/src/contracts/solver/SolverBase.sol";

/**
 * @title AtlasDirectSolver
 * @notice A simple example solver contract that inherits from SolverBase
 * @dev SolverBase is a helper contract that:
 * 1. Implements ISolverContract interface required for all solvers
 * 2. Handles bid payments to Atlas through the payBids modifier
 * 3. Provides security checks via safetyFirst modifier to ensure:
 *    - Only Atlas can call atlasSolverCall
 *    - Only the owner can initiate solver operations
 *    - Proper reconciliation of funds with Atlas escrow
 * 4. Manages WETH/ETH conversions as needed for bid payments
 */
contract AtlasDirectSolver is SolverBase, Ownable {
    bool internal s_shouldSucceed;

    constructor(address weth, address atlas) SolverBase(weth, atlas, msg.sender) Ownable(msg.sender) {
        s_shouldSucceed = true; // should succeed by default, can be set to false
    }

    fallback() external payable { }
    receive() external payable { }

    // Called during the SolverOperation phase
    // This function is called by atlasSolverCall() which forwards the solverOpData calldata
    // by doing: address(this).call{value: msg.value}(solverOpData)
    // where solverOpData contains the ABI-encoded call to solve()
    function solve() public view onlySelf {
        // SolverBase automatically handles paying the bid amount to the Execution Environment through
        // the payBids modifier, as long as this contract has sufficient balance (ETH or WETH)
    }

    // ---------------------------------------------------- //
    //                      ONLY OWNER                      //
    // ---------------------------------------------------- //

    function withdrawETH(address recipient) public onlyOwner {
        SafeTransferLib.safeTransferETH(recipient, address(this).balance);
    }

    function withdrawERC20(address token, address recipient) public onlyOwner {
        SafeTransferLib.safeTransfer(token, recipient, IERC20(token).balanceOf(address(this)));
    }

    // ---------------------------------------------------- //
    //                      MODIFIERS                       //
    // ---------------------------------------------------- //

    // This ensures a function can only be called through atlasSolverCall
    // which includes security checks to work safely with Atlas
    modifier onlySelf() {
        require(msg.sender == address(this), "Not called via atlasSolverCall");
        _;
    }
}
</code></pre>

### **How It Works:**

* The `solve()` function contains the MEV logic.
* The `atlasSolverCall()` function (inherited from `SolverBase`) calls `solve()` by forwarding the callData.
* `solverOpData` is simply the ABI-encoded call to `solve()`.

**Generating `solverOpData`:**

```javascript
const iface = new ethers.utils.Interface(["function solve()"]);
const solverOpData = iface.encodeFunctionData("solve");
```

## Approach 2: Proxying Calls to an External Contract

This approach allows for modularity, enabling the use of a dedicated external contract for various MEV strategies.

The `solverOpData` includes both the function call to your solver contract and the data intended for the external contract.

```solidity
// SolverBase.sol
 ...
function atlasSolverCall(
        address solverOpFrom,
        address executionEnvironment,
        address bidToken,
        uint256 bidAmount,
        bytes calldata solverOpData,
        bytes calldata
    )
        external
        payable
        virtual
        safetyFirst(executionEnvironment, solverOpFrom)
        payBids(executionEnvironment, bidToken, bidAmount)
    {
        (bool success,) = address(this).call{ value: msg.value }(solverOpData);
        if (!success) revert SolverCallUnsuccessful();
    }
```

Example: `AtlasProxySolver`

```solidity
// SPDX-License-Identifier: MIT

pragma solidity 0.8.25;

import { SafeTransferLib } from "solady/utils/SafeTransferLib.sol";
import { ReentrancyGuard } from "solady/utils/ReentrancyGuard.sol";
import { Ownable } from "openzeppelin-contracts/contracts/access/Ownable.sol";
import { IERC20 } from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import { SolverBase } from "../lib/atlas/src/contracts/solver/SolverBase.sol";

/**
 * @title ProxySolver
 * @notice An example solver contract that proxies calls to an external contract.
 * @dev This contract inherits from SolverBase and includes reentrancy guards.
 * It allows the owner to set an external contract to which MEV solution calls are proxied.
 * It includes helper functions to manage the external contract and approved EOAs.
 */
contract AtlasProxySolver is SolverBase, Ownable, ReentrancyGuard {
    address payable private searcherContract;
    mapping(address => bool) internal approvedEOAs;

    constructor(
        address weth,
        address atlas,
        address _searcherContract
    )
        SolverBase(weth, atlas, msg.sender)
        Ownable(msg.sender)
    {
        searcherContract = payable(_searcherContract);
    }

    fallback() external payable { }
    receive() external payable { }

    /**
     * @notice Called during the SolverOperation phase.
     * This function is called via atlasSolverCall(), which forwards the solverOpData calldata.
     * @param _searcherCallData The calldata to be forwarded to the external searcher contract.
     */
    function solve(bytes calldata _searcherCallData) public onlySelf nonReentrant {
        // Call the external searcher contract with the provided calldata.
        (bool success, bytes memory returnedData) = searcherContract.call(_searcherCallData);

        // Revert if the call was unsuccessful.
        require(success, "Searcher call unsuccessful");

        // SolverBase automatically handles paying the bid amount to the Execution Environment.
    }

    // ---------------------------------------------------- //
    //                      ONLY OWNER                      //
    // ---------------------------------------------------- //

    /**
     * @notice Sets the address of the external searcher contract.
     * @param _searcherContract The address of the new searcher contract.
     */
    function setSearcherContractAddress(address _searcherContract) public onlyOwner {
        searcherContract = payable(_searcherContract);
    }

    /**
     * @notice Withdraws all ETH from the contract to a recipient address.
     * @param recipient The address to receive the withdrawn ETH.
     */
    function withdrawETH(address recipient) public onlyOwner {
        SafeTransferLib.safeTransferETH(recipient, address(this).balance);
    }

    /**
     * @notice Withdraws all ERC20 tokens of a specific type from the contract to a recipient address.
     * @param token The address of the ERC20 token contract.
     * @param recipient The address to receive the withdrawn tokens.
     */
    function withdrawERC20(address token, address recipient) public onlyOwner {
        SafeTransferLib.safeTransfer(token, recipient, IERC20(token).balanceOf(address(this)));
    }

    // ---------------------------------------------------- //
    //                      MODIFIERS                       //
    // ---------------------------------------------------- //

    /**
     * @notice Ensures a function can only be called through atlasSolverCall,
     * which includes security checks to work safely with Atlas.
     */
    modifier onlySelf() {
        require(msg.sender == address(this), "Not called via atlasSolverCall");
        _;
    }
}
```

### **How It Works:**

* The `solve(bytes calldata solverOpData)` function receives the callData intended for the external contract.
* It forwards this callData to the `searcherContract` using a low-level `call`.
* `solverOpData` includes the encoded function call for the external contract.

**Generating `solverOpData`:**

Suppose your external searcher contract has a function:

```solidity
function externalSolve(uint256 param1, string memory param2) public {
    // add origin validation here
    // MEV logic here
}
```

#### Step 1: Encode the External Contract Call

```javascript
const externalIface = new ethers.utils.Interface(["function externalSolve(uint256, string)"]);
const externalCallData = externalIface.encodeFunctionData("externalSolve", [param1, param2]);
```

#### Step 2: Encode the Solver Contract Call

```javascript
const solverIface = new ethers.utils.Interface(["function solve(bytes)"]);
const solverOpData = solverIface.encodeFunctionData("solve", [externalCallData]);
```
