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

# Integrating with the USDY_InstantManager contract

> How to programmatically subscribe to and redeem USDY directly on-chain via the USDY_InstantManager contract.

## Overview

USDY is Ondo's yield-bearing token that provides investors a steady return over time. The token price started at \$1.00 in July 2023 and has increased over time at a variable monthly rate. For a product-level introduction, see [USDY Basics](/general-access-products/usdy/basics).

The `USDY_InstantManager` contract is the on-chain entry point used by the Ondo web app to instantly mint and redeem USDY. You can call it directly from your own contracts or EOA to:

* Convert USDC into USDY via `subscribe` (selector `0x22d4a175`)
* Convert USDY back into USDC via `redeem` (selector `0xd8780161`)

Addresses for `USDY`, `USDY_InstantManager`, and the USDY redemption price oracle are listed in [Smart Contracts → Addresses](/addresses).

<Note>
  The Ethereum USDC address used in the examples below is `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48`.
</Note>

## Prerequisites

Before calling `subscribe` or `redeem`, the address that interacts with the contract must be registered in the OndoIDRegistry.

You can whitelist your address at [app.ondo.finance/account/wallets](https://app.ondo.finance/account/wallets). If you run into issues, reach out to [support@ondo.finance](mailto:support@ondo.finance).

<Warning>
  Transactions from an address that is not registered in the OndoIDRegistry will revert with `UserNotRegistered`. Contract wallets and smart-contract integrations must whitelist the exact calling address.
</Warning>

### ERC20 approvals

The `USDY_InstantManager` pulls tokens from your wallet via `transferFrom`, so you must approve it to spend the token you are sending **before** calling `subscribe` or `redeem`:

* Before `subscribe`: approve the manager to spend your **deposit token** (e.g. USDC) for at least `depositAmount`.
* Before `redeem`: approve the manager to spend your **USDY** for at least `rwaAmount`.

Each approval is a separate transaction — typically `IERC20(token).approve(usdyInstantManager, amount)`. If you skip this step, the subscribe/redeem call will revert with an ERC20 allowance error such as `ERC20: insufficient allowance`.

## Subscribing: USDC to USDY

### Function signature

```solidity theme={null}
function subscribe(
    address depositToken,
    uint256 depositAmount,
    uint256 minimumRwaReceived
) external returns (uint256 rwaAmountOut);
```

### Parameters

* **`depositToken`**: the token being deposited (typically USDC)
* **`depositAmount`**: the amount of `depositToken` to deposit, in the token's native decimals (e.g. `1000000` for 1 USDC)
* **`minimumRwaReceived`**: slippage protection, denominated in USDY's 18 decimals. Because you are minting directly with Ondo, there is no front-running or order-size slippage, so `0` is safe.

### Example

```solidity theme={null}
// Swap 100 USDC for USDY
IERC20(USDC).approve(usdyInstantManager, 100e6);
uint256 usdyReceived = usdyInstantManager.subscribe(
    USDC,
    100e6, // 100 USDC (6 decimals)
    0      // no slippage expected when minting directly
);
```

## Redeeming: USDY to USDC

### Function signature

```solidity theme={null}
function redeem(
    uint256 rwaAmount,
    address receivingToken,
    uint256 minimumTokenReceived
) external returns (uint256 receiveTokenAmount);
```

### Parameters

* **`rwaAmount`**: the amount of USDY to redeem, in USDY's 18 decimals (e.g. `1000000000000000000` for 1 USDY)
* **`receivingToken`**: the token to receive (typically USDC)
* **`minimumTokenReceived`**: slippage protection, denominated in the receiving token's native decimals. `0` is safe when redeeming directly with Ondo.

### Example

```solidity theme={null}
// Redeem 100 USDY for USDC
IERC20(USDY).approve(usdyInstantManager, 100e18);
uint256 usdcReceived = usdyInstantManager.redeem(
    100e18, // 100 USDY (18 decimals)
    USDC,
    0       // no slippage expected when redeeming directly
);
```

## USDY price oracle

The USDY price is published on-chain by the `RWADynamicOracle` contract (see the "Redemption Price Oracle" row in [/addresses](/addresses#usdy)). Rather than storing a single current price, the oracle is configured with a series of *ranges* — each range has a start time, end time, and a daily interest rate that compounds across the range. The `USDY_InstantManager` consults this oracle on every subscription and redemption to convert between USD value and USDY amounts.

All prices are denominated in USD with 18 decimals and rounded to 8 decimal places.

### Get the current price

```solidity theme={null}
function getPrice() external view returns (uint256 price);
function getPriceData() external view returns (uint256 price, uint256 timestamp);
```

* **`getPrice()`**: returns the current USDY price, in USD with 18 decimals.
* **`getPriceData()`**: convenience wrapper that also returns the current block timestamp.

Both revert if the oracle is paused.

```solidity theme={null}
uint256 price = usdyOracle.getPrice();
// e.g. 1.087543210000000000 → 1087543210000000000
```

### Get a historical price

```solidity theme={null}
function getPriceHistorical(uint256 timestamp) external view returns (uint256 price);
```

Returns the USDY price at the given Unix timestamp, in USD with 18 decimals.

<Warning>
  If `timestamp` precedes the oracle's first configured range (i.e. before USDY existed on-chain), `getPriceHistorical` returns `0`. Callers should check for a non-zero return value before using the result.
</Warning>

Unlike `getPrice()`, this function does **not** revert when the oracle is paused.

```solidity theme={null}
uint256 oneYearAgo = block.timestamp - 365 days;
uint256 pastPrice = usdyOracle.getPriceHistorical(oneYearAgo);
require(pastPrice > 0, "Timestamp precedes oracle start");
```

### Converting between USD and USDY

The oracle price represents how many USD one USDY is worth.

```solidity theme={null}
// USDY amount (18 decimals) → USD value (18 decimals)
uint256 usdValue = (usdyAmount * oracle.getPrice()) / 1e18;

// USD value (18 decimals) → USDY amount (18 decimals)
uint256 usdyAmount = (usdValue * 1e18) / oracle.getPrice();
```

## Reference

### Decimal handling

* **USDC**: 6 decimals (1 USDC = 1,000,000 units)
* **USDY**: 18 decimals (1 USDY = 10<sup>18</sup> units)
* **Oracle prices**: 18 decimals, rounded to 8 decimal places

### Rate limits and minimums

The manager contract enforces per-user and global rate limits, as well as a configured minimum USD value per subscription and redemption. Very small or unusually large transactions may revert.

### Common errors

| Error                                                | Meaning                                                                   |
| ---------------------------------------------------- | ------------------------------------------------------------------------- |
| `SubscriptionsPaused` / `RedemptionsPaused`          | Operations are temporarily paused on the manager                          |
| `TokenNotAccepted`                                   | The specified deposit or receiving token is not supported                 |
| `UserNotRegistered`                                  | The caller is not registered in the OndoIDRegistry                        |
| `DepositAmountTooSmall` / `RedemptionAmountTooSmall` | Transaction is below the configured USD minimum                           |
| `RwaReceiveAmountTooSmall` / `ReceiveAmountTooSmall` | Output is less than the specified minimum                                 |
| Compliance revert                                    | The caller failed the OndoCompliance check (e.g. sanctions, jurisdiction) |
| Rate-limit revert                                    | The transaction exceeds per-user or global rate limits                    |

### Best practices

1. Ensure the calling address is whitelisted in the OndoIDRegistry before attempting any transaction.
2. Check the contract's pause status (`subscribePaused` / `redeemPaused`) before attempting transactions.
3. Approve the `USDY_InstantManager` for the exact amount being deposited or redeemed.
4. Implement proper error handling for all possible revert conditions.

## Resources

* [Contract addresses](/addresses)
* [Audits](/audits)
* [USDY Basics](/general-access-products/usdy/basics)

<Snippet file="usdy-legal-notice.mdx" />
