> ## Documentation Index
> Fetch the complete documentation index at: https://docs.x402r.org/llms.txt
> Use this file to discover all available pages before exploring further.

# PaymentOperator

> The core payment operator contract with pluggable conditions and fee management

## Overview

The main payment operator contract with pluggable conditions for flexible authorization logic.

* **Type:** Operator instance (one per fee recipient + configuration)
* **Deployment:** Via PaymentOperatorFactory
* **Immutability:** No pause switch, no upgrade path
* **Configuration:** 10 slots for conditions and hooks
* **Use Cases:** Marketplace, subscriptions, streaming, grants, custom flows

## Immutable Fields

```solidity theme={null}
address public immutable ESCROW;              // AuthCaptureEscrow address
address public immutable FEE_RECEIVER;       // Operator fee recipient
ProtocolFeeConfig public immutable PROTOCOL_FEE_CONFIG; // Shared protocol fee config
IFeeCalculator public immutable FEE_CALCULATOR; // Operator fee calculator
```

## State

```solidity theme={null}
// Fee tracking for accurate distribution
mapping(address token => uint256) public accumulatedProtocolFees;

// Fees locked at authorization time
mapping(bytes32 paymentInfoHash => AuthorizedFees) public authorizedFees;
```

## 10-Slot Configuration

<Accordion title="Condition Slots (Before Actions)">
  1. **AUTHORIZE\_PRE\_ACTION\_CONDITION** - Who can authorize payments
  2. **CHARGE\_PRE\_ACTION\_CONDITION** - Who can charge partial amounts
  3. **CAPTURE\_PRE\_ACTION\_CONDITION** - Who can capture funds from escrow
  4. **VOID\_PRE\_ACTION\_CONDITION** - Who can refund during escrow
  5. **REFUND\_PRE\_ACTION\_CONDITION** - Who can refund after capture

  **Default:** `address(0)` = always allow
</Accordion>

<Accordion title="Hook Slots (After Actions)">
  1. **AUTHORIZE\_POST\_ACTION\_HOOK** - Record authorization (for example, timestamp)
  2. **CHARGE\_POST\_ACTION\_HOOK** - Record charge event
  3. **CAPTURE\_POST\_ACTION\_HOOK** - Record capture
  4. **VOID\_POST\_ACTION\_HOOK** - Record void
  5. **REFUND\_POST\_ACTION\_HOOK** - Record refund

  **Default:** `address(0)` = no recording (no-op)
</Accordion>

## Key Methods

### authorize()

Authorizes a payment and locks funds in escrow.

```solidity theme={null}
function authorize(
    AuthCaptureEscrow.PaymentInfo calldata paymentInfo,
    uint256 amount,
    address tokenCollector,
    bytes calldata collectorData
) external nonReentrant
```

**Parameters:**

* `paymentInfo` - Payment info struct (must have `operator == address(this)`, `feeReceiver == address(this)`)
* `amount` - Amount to authorize
* `tokenCollector` - Address of the token collector contract
* `collectorData` - Data to pass to the token collector

**Flow:**

1. Check `AUTHORIZE_PRE_ACTION_CONDITION` (if set)
2. Check fee bounds compatibility
3. Store fees at authorization time (prevents protocol fee changes from breaking capture)
4. Call `escrow.authorize()`
5. Call `AUTHORIZE_POST_ACTION_HOOK` (if set)
6. Emit `AuthorizeExecuted`

**Access:** Controlled by `AUTHORIZE_PRE_ACTION_CONDITION` (default: anyone)

<Tip>
  **Authorization Expiry:** The `PaymentInfo` struct includes an `authorizationExpiry` field (from base commerce-payments). Set this to `type(uint48).max` for no expiry, or specify a timestamp to let the payer reclaim funds after expiry. Subscription-based payments use this to bound the authorization window.
</Tip>

### charge()

Direct charge - collects payment and immediately transfers to receiver (no escrow hold).

```solidity theme={null}
function charge(
    AuthCaptureEscrow.PaymentInfo calldata paymentInfo,
    uint256 amount,
    address tokenCollector,
    bytes calldata collectorData
) external nonReentrant
```

**Parameters:**

* `paymentInfo` - Payment info struct (must have `operator == address(this)`, `feeReceiver == address(this)`)
* `amount` - Amount to charge
* `tokenCollector` - Address of the token collector contract
* `collectorData` - Data to pass to the token collector

**Flow:**

1. Check `CHARGE_PRE_ACTION_CONDITION` (if set)
2. Check fee bounds compatibility
3. Call `escrow.charge()` - funds go directly to receiver
4. Accumulate protocol fees for later distribution
5. Call `CHARGE_POST_ACTION_HOOK` (if set)
6. Emit `ChargeExecuted`

**Access:** Controlled by `CHARGE_PRE_ACTION_CONDITION` (default: anyone)

<Note>
  Unlike `authorize()`, funds go directly to receiver without escrow hold. Refunds are only possible via `refund()`.
</Note>

### capture()

Releases funds from escrow to receiver (capture).

```solidity theme={null}
function capture(
    AuthCaptureEscrow.PaymentInfo calldata paymentInfo,
    uint256 amount,
    bytes calldata data
) external nonReentrant
```

**Parameters:**

* `paymentInfo` - Payment info struct
* `amount` - Amount to capture
* `data` - Optional pass-through data for the pre/post action plugins

**Flow:**

1. Check `CAPTURE_PRE_ACTION_CONDITION` (if set)
2. Use fees stored at authorization time
3. Call `escrow.capture()`
4. Accumulate protocol fees for later distribution
5. Call `CAPTURE_POST_ACTION_HOOK` (if set)
6. Emit `CaptureExecuted`

**Access:** Controlled by `CAPTURE_PRE_ACTION_CONDITION`

<Note>
  **Marketplace example:** Receiver OR StaticAddressCondition(arbiter) + escrow passed
  **Subscription example:** StaticAddressCondition(serviceProvider)
  **DAO example:** StaticAddressCondition(daoMultisig)
</Note>

### void()

Returns all escrowed funds to the payer before capture. Full-only: `escrow.void()` empties the authorization in one transaction.

```solidity theme={null}
function void(
    AuthCaptureEscrow.PaymentInfo calldata paymentInfo,
    bytes calldata data
) external nonReentrant
```

**Parameters:**

* `paymentInfo` - Payment info struct
* `data` - Optional pass-through data for the pre/post action plugins

**Flow:**

1. Check `VOID_PRE_ACTION_CONDITION` (if set)
2. Call `escrow.void()` to return escrowed funds to payer
3. Call `VOID_POST_ACTION_HOOK` (if set)
4. Emit `VoidExecuted`

**Access:** Controlled by `VOID_PRE_ACTION_CONDITION`

<Note>
  **Marketplace example:** StaticAddressCondition(arbiter) for disputes
  **Return policy example:** Receiver OR StaticAddressCondition(arbiter)
  **DAO example:** StaticAddressCondition(daoMultisig)
  **Subscription example:** address(0), no voids allowed
</Note>

<Tip>
  For a partial return, call `capture()` for the amount to keep. Then `void()` the unused authorization, or let the payer reclaim it after `captureDeadline`.
</Tip>

### refund()

Refunds a payment after capture (after the receiver has the funds).

```solidity theme={null}
function refund(
    AuthCaptureEscrow.PaymentInfo calldata paymentInfo,
    uint256 amount,
    address tokenCollector,
    bytes calldata collectorData
) external nonReentrant
```

**Parameters:**

* `paymentInfo` - Payment info struct
* `amount` - Amount to refund to payer
* `tokenCollector` - Address of the token collector that will source the refund
* `collectorData` - Data to pass to the token collector (for example, signatures)

**Flow:**

1. Check `REFUND_PRE_ACTION_CONDITION` (if set)
2. Call `escrow.refund()` - token collector enforces permission
3. Call `REFUND_POST_ACTION_HOOK` (if set)
4. Emit `RefundExecuted`

**Access:** Controlled by `REFUND_PRE_ACTION_CONDITION`. The token collector also enforces permission (for example, the receiver must have approved it, or `collectorData` contains the receiver's signature).

<Note>
  **Marketplace example:** StaticAddressCondition(arbiter) - post-delivery disputes
  **Return policy example:** Receiver - voluntary returns
  **Most configurations:** address(0) - no refunds
</Note>

## Fee System (Modular, Additive)

Fees are additive and modular: `totalFee = protocolFee + operatorFee`

### Fee Architecture

```solidity theme={null}
// Shared protocol fee config (timelocked, swappable calculator)
ProtocolFeeConfig public immutable PROTOCOL_FEE_CONFIG;

// Per-operator fee calculator (immutable, set at deploy)
IFeeCalculator public immutable FEE_CALCULATOR;

// Fee recipients
address public immutable FEE_RECEIVER;  // Operator fee recipient
// Protocol fee recipient is on ProtocolFeeConfig

// Fee tracking for accurate distribution
mapping(address token => uint256) public accumulatedProtocolFees;
```

Fees are additive: `totalFee = protocolFee + operatorFee`, split between `protocolFeeRecipient` and the operator's `FEE_RECEIVER`. For a worked example with concrete amounts, see the [Fee System](/contracts/fees#example-calculation).

**Fee Locking:**
The operator calculates fees at `authorize()` time and stores them in `authorizedFees[hash]`. This stops later protocol fee changes from breaking capture of already-authorized payments.

```solidity theme={null}
struct AuthorizedFees {
    uint16 totalFeeBps;
    uint16 protocolFeeBps;
}
mapping(bytes32 paymentInfoHash => AuthorizedFees) public authorizedFees;
```

**FEE\_RECEIVER** can be:

* Arbiter (marketplace with disputes)
* Service Provider (subscriptions)
* Platform Treasury (platform-controlled)
* DAO Multisig (governance-controlled)

### Fee Distribution

Fees accumulate in the operator contract. Call `distributeFees(token)` to disburse them:

```solidity theme={null}
// Anyone can call to distribute fees for a token
operator.distributeFees(usdcAddress);
// Protocol share -> protocolFeeRecipient
// Operator share -> FEE_RECEIVER
```

### Protocol Fee Changes (7-day Timelock)

Protocol fee calculator and recipient changes require a 7-day timelock on `ProtocolFeeConfig`. See [Fee System: 7-day timelock](/contracts/fees#calculator-changes-7-day-timelock) for the full queue, wait, execute workflow.

<Warning>
  Protocol fee changes require 7-day timelock. Operator fees are immutable (set at deploy time).
</Warning>

## Security Features

* **ReentrancyGuardTransient** - EIP-1153 transient storage for gas-efficient reentrancy protection
* **Ownership** - Solady's Ownable with 2-step transfer
* **Timelock** - 7-day delay on protocol fee changes (operator fees are immutable)
* **Immutable Core** - Escrow, conditions, and fee configuration stay fixed after deployment

## Next Steps

<CardGroup cols={2}>
  <Card title="Periphery Contracts" icon="puzzle-piece" href="/contracts/periphery">
    AuthCaptureEscrow, RefundRequest, and other supporting contracts.
  </Card>

  <Card title="Conditions" icon="filter" href="/contracts/conditions/overview">
    Explore the pluggable condition system.
  </Card>

  <Card title="Factories" icon="industry" href="/contracts/factories">
    Deploy operators with factory patterns.
  </Card>

  <Card title="Examples" icon="code" href="/contracts/examples">
    See real-world configuration examples.
  </Card>
</CardGroup>
