> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/zkp2p/zkp2p-contracts/llms.txt
> Use this file to discover all available pages before exploring further.

# RateManagerV1

> Delegated rate manager with manager-owned rates and depositor-owned floors

# RateManagerV1 Contract

RateManagerV1 is a canonical delegated rate manager that allows rate managers to set conversion rates on behalf of depositors while giving depositors the ability to configure floor protections. This enables dynamic rate management with depositor safety controls.

## Overview

* **Contract**: `RateManagerV1.sol`
* **Inherits**: `Ownable`, `IRateManager`
* **Purpose**: Delegated rate management with manager-owned rates and depositor-owned per-deposit floors

## Key Concepts

### Delegation Model

Depositors can delegate rate management to a professional rate manager who:

* Sets conversion rates for payment method/currency pairs
* Collects optional fees on fulfilled intents
* Manages rates across multiple deposits

Depositors retain control through:

* Fixed floor rates that manager rates cannot go below
* Oracle-based floor rates with spread protection
* Ability to enable/disable specific currency pairs
* Ability to opt-out at any time

## State Variables

<ParamField path="escrowRegistry" type="IEscrowRegistry">
  Registry of whitelisted escrow contracts
</ParamField>

<ParamField path="nextRateManagerId" type="uint256">
  Counter for generating unique rate manager IDs
</ParamField>

## Core Functions

### Rate Manager Creation

#### createRateManager

Creates a new rate manager configuration.

<ParamField path="_config" type="RateManagerConfig">
  Rate manager configuration:

  * `manager`: Manager address that can set rates
  * `feeRecipient`: Address to receive manager fees
  * `maxFee`: Maximum fee this manager can charge (immutable)
  * `fee`: Current fee (must be less than or equal to maxFee)
  * `minLiquidity`: Minimum deposit liquidity required for opt-in
  * `name`: Display name for the manager
  * `uri`: Metadata URI for additional info
</ParamField>

```solidity theme={null}
function createRateManager(RateManagerConfig calldata _config) 
    external 
    returns (bytes32 rateManagerId)
```

<ResponseField name="rateManagerId" type="bytes32">
  Newly created manager ID
</ResponseField>

**Events Emitted:**

* `RateManagerCreated(rateManagerId, manager, feeRecipient, maxFee, fee, name, uri)`
* `MinLiquidityUpdated(rateManagerId, minLiquidity)` (if minLiquidity > 0)

**Example:**

```solidity theme={null}
RateManagerV1.RateManagerConfig memory config = RateManagerV1.RateManagerConfig({
    manager: managerAddress,
    feeRecipient: feeRecipient,
    maxFee: 3e16, // 3% max
    fee: 1e16,    // 1% current fee
    minLiquidity: 1000e6, // 1000 USDC minimum
    name: "Premium Rate Manager",
    uri: "https://example.com/manager.json"
});

bytes32 managerId = rateManager.createRateManager(config);
```

### Manager Configuration

#### setRateManagerConfig

Updates mutable manager config fields.

<ParamField path="_rateManagerId" type="bytes32">
  Manager ID
</ParamField>

<ParamField path="_manager" type="address">
  New manager address
</ParamField>

<ParamField path="_feeRecipient" type="address">
  New fee recipient
</ParamField>

<ParamField path="_name" type="string">
  New display name
</ParamField>

<ParamField path="_uri" type="string">
  New metadata URI
</ParamField>

```solidity theme={null}
function setRateManagerConfig(
    bytes32 _rateManagerId,
    address _manager,
    address _feeRecipient,
    string calldata _name,
    string calldata _uri
) external onlyManager(_rateManagerId)
```

#### setFee

Updates manager fee. Must be less than or equal to maxFee.

```solidity theme={null}
function setFee(bytes32 _rateManagerId, uint256 _fee) 
    external onlyManager(_rateManagerId)
```

**Events Emitted:**

* `RateManagerFeeUpdated(rateManagerId, fee)`

#### setMinLiquidity

Updates minimum liquidity requirement for deposit opt-in.

```solidity theme={null}
function setMinLiquidity(bytes32 _rateManagerId, uint256 _minLiquidity) 
    external onlyManager(_rateManagerId)
```

**Events Emitted:**

* `MinLiquidityUpdated(rateManagerId, minLiquidity)`

### Rate Management

#### setRate

Sets manager-side rate for one payment/currency tuple.

<ParamField path="_rateManagerId" type="bytes32">
  Manager ID
</ParamField>

<ParamField path="_paymentMethod" type="bytes32">
  Payment method key
</ParamField>

<ParamField path="_currencyCode" type="bytes32">
  Currency key
</ParamField>

<ParamField path="_rate" type="uint256">
  New rate in precise units (1e18 = 1:1)
</ParamField>

```solidity theme={null}
function setRate(
    bytes32 _rateManagerId,
    bytes32 _paymentMethod,
    bytes32 _currencyCode,
    uint256 _rate
) external onlyManager(_rateManagerId)
```

**Events Emitted:**

* `RateManagerRateUpdated(rateManagerId, paymentMethod, currencyCode, rate)`

**Example:**

```solidity theme={null}
// Set USD rate for Venmo to 0.99 USDC per USD
rateManager.setRate(
    managerId,
    venmoHash,
    usdHash,
    0.99e18
);
```

#### setRateBatch

Batch sets manager-side rates for multiple tuples.

<ParamField path="_rateManagerId" type="bytes32">
  Manager ID
</ParamField>

<ParamField path="_paymentMethods" type="bytes32[]">
  Payment method keys
</ParamField>

<ParamField path="_currencyCodes" type="bytes32[][]">
  Currency keys grouped by payment method index
</ParamField>

<ParamField path="_rates" type="uint256[][]">
  Rates grouped by payment method index
</ParamField>

```solidity theme={null}
function setRateBatch(
    bytes32 _rateManagerId,
    bytes32[] calldata _paymentMethods,
    bytes32[][] calldata _currencyCodes,
    uint256[][] calldata _rates
) external onlyManager(_rateManagerId)
```

**Events Emitted:**

* `RateManagerRateUpdated(...)` for each rate
* `RateManagerRatesBatchUpdated(rateManagerId, totalUpdated)`

**Example:**

```solidity theme={null}
bytes32[] memory paymentMethods = new bytes32[](2);
paymentMethods[0] = venmoHash;
paymentMethods[1] = cashappHash;

bytes32[][] memory currencies = new bytes32[][](2);
currencies[0] = new bytes32[](1);
currencies[0][0] = usdHash;
currencies[1] = new bytes32[](1);
currencies[1][0] = usdHash;

uint256[][] memory rates = new uint256[][](2);
rates[0] = new uint256[](1);
rates[0][0] = 0.99e18; // Venmo USD
rates[1] = new uint256[](1);
rates[1][0] = 0.98e18; // CashApp USD

rateManager.setRateBatch(managerId, paymentMethods, currencies, rates);
```

### Depositor Floor Configuration

#### setDepositorFloor

Sets depositor floor config for one delegated tuple. Only callable by deposit owner.

<ParamField path="_rateManagerId" type="bytes32">
  Manager ID
</ParamField>

<ParamField path="_escrow" type="address">
  Escrow address
</ParamField>

<ParamField path="_depositId" type="uint256">
  Deposit ID
</ParamField>

<ParamField path="_paymentMethod" type="bytes32">
  Payment method key
</ParamField>

<ParamField path="_currencyCode" type="bytes32">
  Currency key
</ParamField>

<ParamField path="_config" type="DepositorFloorConfig">
  Floor configuration:

  * `enabled`: Whether this tuple is enabled
  * `floorFixed`: Fixed floor rate
  * `floorSpreadBps`: Oracle spread in basis points (0-10000)
  * `oracleAdapter`: Oracle adapter address (address(0) for no oracle)
  * `adapterConfig`: Oracle adapter configuration bytes
  * `maxStaleness`: Max oracle staleness in seconds
</ParamField>

```solidity theme={null}
function setDepositorFloor(
    bytes32 _rateManagerId,
    address _escrow,
    uint256 _depositId,
    bytes32 _paymentMethod,
    bytes32 _currencyCode,
    DepositorFloorConfig calldata _config
) external
```

**Events Emitted:**

* `DepositorFloorSet(rateManagerId, escrow, depositId, paymentMethod, currencyCode, ...)`

**Example: Fixed Floor**

```solidity theme={null}
RateManagerV1.DepositorFloorConfig memory config = RateManagerV1.DepositorFloorConfig({
    enabled: true,
    floorFixed: 0.95e18, // Never accept rates below 0.95 USDC per USD
    floorSpreadBps: 0,
    oracleAdapter: address(0),
    adapterConfig: "",
    maxStaleness: 0
});

rateManager.setDepositorFloor(
    managerId,
    escrowAddress,
    depositId,
    venmoHash,
    usdHash,
    config
);
```

**Example: Oracle Floor with Spread**

```solidity theme={null}
RateManagerV1.DepositorFloorConfig memory config = RateManagerV1.DepositorFloorConfig({
    enabled: true,
    floorFixed: 0.90e18,        // Fallback fixed floor
    floorSpreadBps: 200,        // 2% above oracle rate
    oracleAdapter: oracleAddr,  // Chainlink or other oracle
    adapterConfig: adapterConfig, // Oracle-specific config
    maxStaleness: 3600          // 1 hour max staleness
});

rateManager.setDepositorFloor(managerId, escrowAddress, depositId, venmoHash, usdHash, config);
```

#### setDepositorFloorBatch

Batch sets depositor floors for one deposit.

```solidity theme={null}
function setDepositorFloorBatch(
    bytes32 _rateManagerId,
    address _escrow,
    uint256 _depositId,
    bytes32[] calldata _paymentMethods,
    bytes32[][] calldata _currencyCodes,
    DepositorFloorConfig[][] calldata _configs
) external
```

#### setDepositorCurrencyEnabled

Sets depositor-side currency enabled state. Only callable by deposit owner.

```solidity theme={null}
function setDepositorCurrencyEnabled(
    bytes32 _rateManagerId,
    address _escrow,
    uint256 _depositId,
    bytes32 _paymentMethod,
    bytes32 _currencyCode,
    bool _enabled
) external
```

**Events Emitted:**

* `DepositorCurrencyEnabledSet(rateManagerId, escrow, depositId, paymentMethod, currencyCode, enabled)`

### Callbacks

#### onDepositOptIn

Callback invoked by EscrowV2 when a deposit opts into this manager. Validates minimum liquidity requirement.

```solidity theme={null}
function onDepositOptIn(
    uint256 _depositId,
    bytes32 _rateManagerId
) external view override
```

## View Functions

### getRate

Returns manager-adjusted rate for a delegated deposit tuple.

```solidity theme={null}
function getRate(
    bytes32 _rateManagerId,
    address _escrow,
    uint256 _depositId,
    bytes32 _paymentMethod,
    bytes32 _currencyCode
) external view override returns (uint256 rate)
```

<ResponseField name="rate" type="uint256">
  Effective delegated rate (max of manager rate and depositor floor). Returns 0 if disabled or no manager rate set.
</ResponseField>

**Rate Calculation Logic:**

1. Check if depositor has enabled this tuple (return 0 if disabled)
2. Get manager rate (return 0 if not set)
3. Compute depositor's effective floor:
   * If oracle configured: `max(floorFixed, oracleRate * (1 + floorSpreadBps/10000))`
   * Otherwise: `floorFixed`
4. Return `max(managerRate, effectiveFloor)`
5. If oracle configured but returns 0 and no fixed floor, return 0 (safety protection)

### getFee

Returns fee recipient and fee for a manager ID.

```solidity theme={null}
function getFee(bytes32 _rateManagerId) 
    external view override 
    returns (address recipient, uint256 fee)
```

### isRateManager

Returns whether a manager ID exists.

```solidity theme={null}
function isRateManager(bytes32 _rateManagerId) 
    public view override 
    returns (bool exists)
```

### getRateManager

Returns full manager config for a manager ID.

```solidity theme={null}
function getRateManager(bytes32 _rateManagerId) 
    external view 
    returns (RateManagerConfig memory config)
```

### getManagerRate

Returns manager-set rate for one tuple (without floor logic).

```solidity theme={null}
function getManagerRate(
    bytes32 _rateManagerId,
    bytes32 _paymentMethod,
    bytes32 _currencyCode
) external view returns (uint256 rate)
```

### getDepositorFloor

Returns depositor floor config for a delegated tuple.

```solidity theme={null}
function getDepositorFloor(
    bytes32 _rateManagerId,
    address _escrow,
    uint256 _depositId,
    bytes32 _paymentMethod,
    bytes32 _currencyCode
) external view returns (DepositorFloorConfig memory config)
```

### isDepositorCurrencyEnabled

Returns whether a tuple is enabled for the deposit.

```solidity theme={null}
function isDepositorCurrencyEnabled(
    bytes32 _rateManagerId,
    address _escrow,
    uint256 _depositId,
    bytes32 _paymentMethod,
    bytes32 _currencyCode
) external view returns (bool enabled)
```

## Constants

<ParamField path="GLOBAL_MAX_MANAGER_FEE" type="uint256">
  `5e16` - Global maximum manager fee (5%)
</ParamField>

<ParamField path="BPS" type="uint256">
  `10_000` - Basis points for percentage calculations
</ParamField>

<ParamField path="MAX_ADAPTER_CONFIG_BYTES" type="uint256">
  `256` - Maximum oracle adapter config size
</ParamField>

## Events

### RateManagerCreated

```solidity theme={null}
event RateManagerCreated(
    bytes32 indexed rateManagerId,
    address indexed manager,
    address indexed feeRecipient,
    uint256 maxFee,
    uint256 fee,
    string name,
    string uri
)
```

### RateManagerRateUpdated

```solidity theme={null}
event RateManagerRateUpdated(
    bytes32 indexed rateManagerId, 
    bytes32 indexed paymentMethod, 
    bytes32 indexed currencyCode, 
    uint256 rate
)
```

### DepositorFloorSet

```solidity theme={null}
event DepositorFloorSet(
    bytes32 indexed rateManagerId,
    address indexed escrow,
    uint256 indexed depositId,
    bytes32 paymentMethod,
    bytes32 currencyCode,
    uint256 floorFixed,
    uint16 floorSpreadBps,
    address oracleAdapter,
    bytes adapterConfig,
    uint32 maxStaleness,
    bool enabled
)
```

## Use Cases

### Professional Rate Management

Rate managers can:

* Manage conversion rates across multiple depositors
* Adjust rates based on market conditions
* Collect fees for their service
* Build reputation and attract more depositors

### Depositor Protection

Depositors can:

* Set minimum acceptable rates (floors)
* Use oracle-based dynamic floors with spread protection
* Enable/disable specific currency pairs
* Opt-out at any time by clearing the rate manager

### Example: Complete Integration

```solidity theme={null}
// 1. Manager creates rate manager
bytes32 managerId = rateManager.createRateManager(config);

// 2. Manager sets rates
rateManager.setRate(managerId, venmoHash, usdHash, 0.99e18);

// 3. Depositor opts into rate manager on EscrowV2
escrow.setRateManager(depositId, address(rateManager), managerId);

// 4. Depositor sets floor protection
rateManager.setDepositorFloor(
    managerId,
    address(escrow),
    depositId,
    venmoHash,
    usdHash,
    floorConfig
);

// 5. Depositor enables the currency pair
rateManager.setDepositorCurrencyEnabled(
    managerId,
    address(escrow),
    depositId,
    venmoHash,
    usdHash,
    true
);

// 6. Intent takers see the effective rate
uint256 effectiveRate = escrow.getEffectiveRate(
    depositId,
    venmoHash,
    usdHash
); // Returns max(managerRate, depositorFloor)
```
