# Bundle Requirements

Transaction Requirements for Solver Operations

1. **Gas Parameters for `userOpHash` Generation**
   * **Legacy Transactions**:
     * **`gasPrice`**: Must match the opportunity-creating transaction.
   * **Type 2 (EIP-1559) Transactions**:
     * **`maxFeePerGas`** and **`maxPriorityFeePerGas`**: Must match the opportunity-creating transaction.
   * **Implementation**:
     * Ensure meta transactions (EIP-712) use gas parameters identical to the opportunity-creating transaction to accurately generate `userOpHash`.
2. **`userOpHash` Generation**
   * **Purpose**: Identifies the opportunity transaction in the PFL-Auction context
   * **Procedure**:
     * Call the `PFL-Auction` `dAppControl` contract with the matched gas parameters.
     * The transaction type influences the gas parameters used but does not need separate handling.\

3. **Solver Operation Handling**
   * **Behavior**:
     * Does **not** differentiate between legacy and Type 2 transactions.
     * Relies solely on the correctly generated `userOpHash` for processing.
   * **Implications**:
     * No adjustments needed within the solver for different transaction types.

Please follow [Bundle Format](bundle-format) guide for more detailed guide for Solver Operation&#x20;

{% hint style="warning" %}
Note: In Atlas, the transaction hash alone is not sufficient. Instead, we incorporate additional Atlas-specific parameters and configuration details, combining them with the original transaction hash to create a new, unique identifier. This rehashing process ensures that each transaction reflects Atlas-specific context and configurations accurately.
{% endhint %}

The Example below show how to obtain the correct `userOpHash` to be passed as reference ot the targeted opportunity transaction.



```javascript
import { Contract, Interface, JsonRpcProvider, keccak256, parseEther, TypedDataDomain, Wallet } from "ethers";


const provider = new JsonRpcProvider("https://polygon.llamarpc.com");

const dappControlAddr = "0x3e23e4282FcE0cF42DCd0E9bdf39056434E65C1F"; // current dappControl address (review docs)
const PFLControlAbi = [
  {
    "inputs": [
      { "internalType": "bytes32", "name": "oppTxHash", "type": "bytes32" },
      { "internalType": "uint256", "name": "oppTxMaxFeePerGas", "type": "uint256" },
      { "internalType": "uint256", "name": "oppTxMaxPriorityFeePerGas", "type": "uint256" },
      { "internalType": "address", "name": "fastLaneSigner", "type": "address" }
    ],
    "name": "getBackrunUserOpHash",
    "outputs": [{ "internalType": "bytes32", "name": "userOpHash", "type": "bytes32" }],
    "stateMutability": "view",
    "type": "function"
  },
];
const dappControl = new Contract(dappControlAddr, PFLControlAbi, provider);


async function main() {
  const feeData = await provider.getFeeData();

  const opportunityRawTx = "0x000"; //binary string of opportunity tx
  const isLegacyTx = isLegacy(opportunityRawTx);
  
  //match opportunity tx transaction type
  const maxFeePerGas = isLegacyTx ? feeData.gasPrice: feeData.maxFeePerGas;
  const maxPriorityFeePerGas = isLegacyTx ? feeData.gasPrice : feeData.maxPriorityFeePerGas,
   
  // Get the userOpHash for the opportunity tx calling the PFL dappControl contract
  //NOTE: we need to use the same transaction type as the opportunity tx
  const userOpHash = await dappControl.getBackrunUserOpHash(
      keccak256(opportunityRawTx),
      maxFeePerGas,
      maxPriorityFeePerGas,
      dAppOpSignerAddr
  );
  
  // additional code for generation of the solver operation and bidSubmission
  
}

main().catch(console.error);
```
