Skip to main content

Solver Concepts

SolverOperation Struct

The SolverOperation struct is the fundamental data structure that solvers must work with. It contains all the necessary information for executing an operation within the Atlas Protocol.

struct SolverOperation {
address from;
address to;
uint256 value;
uint256 gas;
uint256 maxFeePerGas;
uint256 deadline;
address solver;
address control;
bytes32 userOpHash;
address bidToken;
uint256 bidAmount;
bytes data;
bytes signature;
}

Solver Interface

Searchers need to implement the following interface in their smart contracts:

interface ISolverContract {
function atlasSolverCall(
address solverOpFrom,
address executionEnvironment,
address bidToken,
uint256 bidAmount,
bytes calldata solverOpData,
bytes calldata extraReturnData
)
external
payable;
}

This interface defines the atlasSolverCall function, which is the entry point for the Atlas Protocol to interact with the searcher's contract.

Sequential Diagram of the Solver

The following diagram illustrates the key interactions between the Bundler, DAppContract, Atlas, ExecutionEnvironment, and SolverContract components in the Atlas Protocol ecosystem:

Helper Base Contracts

The Atlas Protocol provides two helper base contracts that developers can inherit from to streamline the creation of Solvers:

SolverBase

SolverBase is a foundational contract for Solvers designed to work with DAppControl contracts that have the invertBidValue flag set to false.

  • Safety checks
  • Escrow reconciliation
  • Bid payment processing

SolverBaseInvertBid

SolverBaseInvertBid extends the functionalities of SolverBase to support DAppControl contracts with the invertBidValue flag set to true. It introduces:

  • Mechanisms for bid retrieval
  • Support for inverted bid values
  • Proper bid processing and allocation

Example: Inheriting from SolverBase

contract MyCustomSolver is SolverBase {
constructor(address weth, address atlasEscrow, address owner)
SolverBase(weth, atlasEscrow, owner)
{}

function atlasSolverCall(
address solverOpFrom,
address executionEnvironment,
address bidToken,
uint256 bidAmount,
bytes calldata solverOpData,
bytes calldata extraReturnData
)
external
payable
override(SolverBase)
safetyFirst(executionEnvironment, solverOpFrom)
payBids(executionEnvironment, bidToken, bidAmount)
{
// Custom solver logic here
(bool success,) = address(this).call{value: msg.value}(solverOpData);
if (!success) revert SolverCallUnsuccessful();
}
}

Important Modifiers

When inheriting from SolverBase, it's crucial to use these modifiers correctly in your atlasSolverCall function implementation to ensure proper security checks and bid payments:

1. safetyFirst Modifier

modifier safetyFirst(address executionEnvironment, address solverOpFrom) {
if (msg.sender != _atlas) revert InvalidEntry();
if (solverOpFrom != _owner) revert InvalidCaller();

_;

uint256 shortfall = IAtlas(_atlas).shortfall();

if (shortfall < msg.value) shortfall = 0;
else shortfall -= msg.value;

if (msg.value > address(this).balance) {
IWETH9(WETH_ADDRESS).withdraw(msg.value - address(this).balance);
}

IAtlas(_atlas).reconcile{ value: msg.value }(shortfall);
}

This modifier:

  • Ensures that only the Atlas contract can call the function.
  • Verifies that the solver operation is from the authorized owner.
  • Handles any shortfall in the Atlas contract after the main function execution.
  • Unwraps WETH if necessary to cover the msg.value.
  • Reconciles the shortfall with the Atlas contract.

2. payBids Modifier

modifier payBids(address executionEnvironment, address bidToken, uint256 bidAmount) {
_;

if (bidToken == address(0)) {
// Pay bid in ETH
if (bidAmount > address(this).balance) {
IWETH9(WETH_ADDRESS).withdraw(bidAmount - address(this).balance);
}
SafeTransferLib.safeTransferETH(executionEnvironment, bidAmount);
} else {
// Pay bid in ERC20 (bidToken)
SafeTransferLib.safeTransfer(bidToken, executionEnvironment, bidAmount);
}
}

This modifier:

  • Handles the payment of the solver's bid to the Execution Environment.
  • Supports payments in both ETH (Native) and ERC20 tokens.
  • Unwraps WETH if necessary to cover ETH payments.
  • Uses SafeTransferLib for secure token transfers.