> For the complete documentation index, see [llms.txt](https://tech.usual.money/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://tech.usual.money/smart-contracts/utility-contracts/eur0/monerium-swapper-helper.md).

# Monerium Swapper Helper

### **High-Level Overview**

The `SwapperHelper` contract is a helper utility that performs 1:1 swaps between a collateral token and a stablecoin on behalf of a user. It coordinates a three-way token movement where:

* The **caller** supplies stablecoin (EUR0) and receives collateral (EURe).
* The **recipient** supplies collateral (EURe) and receives stablecoin (EUR0).

The contract supports both standard ERC20 approvals and ERC20 Permit-based approvals (EIP-2612) for the collateral token, enabling gasless approval flows for EOAs. An optional `operator` role can be configured to restrict who is allowed to initiate swaps.

### **Contract Summary**

`SwapperHelper` sits between a collateral token (EURe) and a stablecoin (EUR0) and enforces a 1:1 exchange rate between them, assuming they share the same number of decimals. The contract.

### **Key Features**

**1:1 Swap Mechanism**

* Swaps collateral and stablecoin at a 1:1 rate, enforced by equal decimals on both tokens.
* The caller ends up with collateral; the recipient ends up with stablecoin.

**Permit-Based Approval Flow**

* `swapOnBehalfWithPermit` uses `IERC20Permit` to approve collateral spending via signature.
* Allows recipients to authorize swaps without an on-chain approval transaction (EOA only).

### **Functions Description**

#### **Public / External Functions**

* **`swapOnBehalfWithPermit(address recipient, uint256 maxAmount, uint256 deadline, uint8 v, bytes32 r, bytes32 s)`** \
  Performs a 1:1 swap using an ERC20 Permit signature for collateral.
  * **Parameters**:
    * `recipient`: Address providing collateral and receiving stablecoin.
    * `maxAmount`: Maximum collateral amount to swap (and stablecoin to transfer).
    * `deadline`: Permit deadline; reverts if `block.timestamp > deadline`.
    * `v`, `r`, `s`: ECDSA signature components for the permit.
  * **Requirements**:
    * `COLLATERAL_TOKEN` supports `permit`.
    * Signature must authorize `recipient` → `this` for `maxAmount` until `deadline`.
    * Caller must have approved sufficient stablecoin allowance to `this`.
    * `deadline` must not be expired; otherwise reverts with `DeadlineExpired()`.
    * Operator check must pass (see `_swapOnBehalf`).
* **`swapOnBehalf(address recipient, uint256 maxAmount)`** \
  Performs a 1:1 swap based on pre-existing ERC20 approvals (no permit).
  * **Parameters**:
    * `recipient`: Address providing collateral and receiving stablecoin.
    * `maxAmount`: Maximum collateral amount to swap (and stablecoin to transfer).
  * **Requirements**:
    * `recipient` must have approved this contract to spend collateral.
    * Caller must have approved this contract to spend stablecoin.
    * Operator check must pass.
* **`changeOperator(address newOperator)`** \
  Updates the `operator` address.
  * **Parameters**:
    * `newOperator`: New operator address (can be zero to make swaps permissionless).

### **State Variables**

* **`COLLATERAL_TOKEN`**\
  Collateral token is **EURe** and used in swaps (must implement `permit` for `swapOnBehalfWithPermit`).
* **`STABLECOIN`**\
  Stablecoin token is **EUR0** and used in swaps.
* **`operator`**\
  Optional operator address restricting who can initiate swaps. `address(0)` means permissionless.

### **Error Handling**

* **`NullAddress()`**: Thrown when a required address parameter is zero.
* **`DeadlineExpired()`**: Thrown when a provided permit deadline has already passed.
* **`ZeroAmount()`**: Thrown when a swap or recovery amount resolves to zero.
* **`NotAuthorized()`**: Thrown when a non-operator initiates a swap while an operator is configured.
* **`InsufficientBalance()`**: Thrown if stablecoin balance check after transfer fails, indicating an unexpected token behavior.
* **`InvalidDecimals()`**: Thrown in the constructor when collateral and stablecoin decimals differ.
* **`NotAllowed()`**: Thrown when attempting to renounce ownership.
* **`SameValue()`**: Thrown when collateral and stablecoin addresses are the same.

### **Security Considerations**

#### **Immutable Token References**

* `COLLATERAL_TOKEN` and `STABLECOIN` are `immutable` and set once in the constructor.
* Prevents arbitrary token reconfiguration.

#### **Decimal Consistency**

* Validates equal decimals for collateral and stablecoin at deployment.
* Ensures 1:1 swaps are value-consistent in token units.

#### **Operator Access Control**

* Optional operator limit reduces who can execute swaps in controlled environments.
* Owner can update the operator or set it to zero for permissionless use.

#### **Balance Verification**

* After transferring stablecoin from caller to contract, the contract checks that its balance increased as expected.
* Protects against non-standard ERC20 implementations that do not behave as expected.

#### **Reentrancy and Token Safety**

* Uses `SafeERC20` for all token transfers.
* The stablecoin and collateral transfers are ordered to minimize risk; the final transfer (`safeTransferFrom` of collateral) is from the recipient to the caller.
* Comments acknowledge arbitrary ERC20 sends, justified because the recipient is the intended beneficiary of stablecoin.

#### **Ownership Retention**

* Ownership cannot be renounced, ensuring a responsible address for operator and recovery actions.

#### **Token Recovery**

* Owner-only `recoverERC20` prevents tokens from being permanently stuck in the contract.

### **Integration Notes**

* **Token Requirements**
  * `COLLATERAL_TOKEN`:
    * Must be ERC20-compliant.
    * Must implement `IERC20Permit` for the permit-based swap function.
  * `STABLECOIN`:
    * Standard ERC20.
  * Both tokens must:
    * Have identical `decimals()`.
    * Be distinct addresses.
* **Using `swapOnBehalfWithPermit`**
  1. Recipient signs an ERC20 Permit approving this contract to spend up to `maxAmount` collateral.
  2. Caller provides the signature parameters and `maxAmount`.
  3. Contract attempts the permit (non-fatal if it fails) and then swaps up to the minimum of:
     * Recipient’s collateral allowance to the contract.
     * Recipient’s collateral balance.
     * Provided `maxAmount`.
* **Using `swapOnBehalf`**
  1. Recipient approves this contract to spend collateral.
  2. Caller approves this contract to spend stablecoin.
  3. Caller calls `swapOnBehalf(recipient, maxAmount)`.
  4. Swap executes for the capped amount as above.
* **Operator Configuration**
  * For open, permissionless swaps, deploy with `_operator = address(0)` or later call `changeOperator(address(0))`.
  * For controlled environments (e.g., only a specific router or backend), set `_operator` to that address.
* **Event Usage**
  * Listen to `SwapOnBehalf(caller, recipient, amount)` (defined in `ISwapperHelper`) to index executed swaps.
  * Listen to `OperatorChanged(newOperator)` to track operator role changes.
