Skip to main content

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. 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.
The Ethereum USDC address used in the examples below is 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48.

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. If you run into issues, reach out to support@ondo.finance.
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.

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

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

// 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

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

// 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). 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

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.
uint256 price = usdyOracle.getPrice();
// e.g. 1.087543210000000000 → 1087543210000000000

Get a historical price

function getPriceHistorical(uint256 timestamp) external view returns (uint256 price);
Returns the USDY price at the given Unix timestamp, in USD with 18 decimals.
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.
Unlike getPrice(), this function does not revert when the oracle is paused.
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.
// 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 = 1018 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

ErrorMeaning
SubscriptionsPaused / RedemptionsPausedOperations are temporarily paused on the manager
TokenNotAcceptedThe specified deposit or receiving token is not supported
UserNotRegisteredThe caller is not registered in the OndoIDRegistry
DepositAmountTooSmall / RedemptionAmountTooSmallTransaction is below the configured USD minimum
RwaReceiveAmountTooSmall / ReceiveAmountTooSmallOutput is less than the specified minimum
Compliance revertThe caller failed the OndoCompliance check (e.g. sanctions, jurisdiction)
Rate-limit revertThe 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