# Huma Finance (/docs/nodes/defi/huma)

Huma 2.0 PayFi yield on Solana: PST APY, price and pool liquidity, wallet balances, USDC deposits with optional lockups, queued redemptions, native instant withdrawals, and claims.



The Huma Finance node talks to the [Huma 2.0](https://docs.huma.finance/products/huma-2.0/overview) permissionless pool on Solana through Huma's official SDK. Depositing USDC mints PST, the PayFi Strategy Token (USDC yield plus Huma Feathers rewards). The older Maxi mode minted mPST; Huma retired it in April 2026, and existing mPST positions can still be read and redeemed here. PST represents a share of pool assets, and its USDC redemption value grows as yield accrues. PST is a normal SPL token: it trades against USDC on Jupiter and Meteora, and it can be used as collateral on Kamino.

No API key is needed. Reads come from the Huma program on chain and from Huma's public rewards API. The four operations that move funds, `deposit`, `requestWithdrawal`, `instantWithdraw`, and `claimProcessed`, sign with your connected wallet: Solaris AI builds the transaction, decodes it, refuses anything outside the expected shape, signs it through your embedded wallet, and broadcasts it. No private key ever leaves the platform, and every signing operation carries a **Dry run** switch that builds and simulates the transaction without signing.

PST has three ways out, and the node covers all of them. A **queued redemption** (`requestWithdrawal`) pays NAV with no fee, but Huma processes it later under a daily cap. A **native instant withdrawal** (`instantWithdraw`) burns PST for USDC in the same transaction at NAV minus a fee that depends on how liquid the pool is at that moment. A **secondary swap** on [Relay](/docs/nodes/defi/relay) or [Jupiter](/docs/nodes/defi/jupiter) sells PST at the market price, outside every Huma cap. `getPoolStatus` and a dry run of `instantWithdraw` give you the numbers to choose.

Prerequisites [#prerequisites]

* **Read operations**: nothing.
* **`deposit` and `requestWithdrawal`**: a connected wallet with server-side signing authorized, the USDC or PST being moved, and about 0.01 SOL for account rent and network fees. The first deposit in a mode creates a lender account and a token account for that mode; a withdrawal from a wallet that received its tokens by transfer or swap creates the lender account in the same transaction.

What to build with it [#what-to-build-with-it]

* **Yield monitor**: a cron trigger once a day, `getApy` in Classic mode, a Condition on `{humaResponse.data.totalApyPercent}`, and a Telegram message when the APY drops below your floor.
* **Park idle USDC**: a Balance node reading the wallet's USDC, a Condition on the amount, then `deposit` with the amount templated from the balance. Run it with Dry run first; the output carries the simulation result and any funding gap.
* **Slow exit with a receipt**: `requestWithdrawal` for the unlocked balance from `getBalances`, then a daily `getBalances` until `pendingRedemptions` reads zero, then a Discord message.
* **Fast exit**: `getBalances`, then a [Relay](/docs/nodes/defi/relay) or [Jupiter](/docs/nodes/defi/jupiter) swap from the PST mint (`59obFNBzyTBGowrkif5uK7ojS58vsuWz3ZCvg6tfZAGw`) to USDC. The swap settles immediately and never touches the redemption queue or its daily cap.
* **Best-route exit**: `instantWithdraw` with Dry run on for the exact net USDC Huma would pay right now, a Jupiter quote for the same PST, a Condition comparing the two, then either the live `instantWithdraw` or the swap. Add `getBalances` first and refuse the run when `pendingRequests` is not zero or the amount exceeds `unlocked`.
* **Sweep processed redemptions**: a daily `claimProcessed`. It reads the chain and signs nothing when there is nothing to claim.

Operations [#operations]

Every operation takes a **Mode**: `classic` for PST or `maxi` for mPST. The two modes are separate positions with their own APY, price, balances, and token account. Huma retired Maxi mode in April 2026 (new deposits and switches disabled, rewards ended 26 May 2026), so `maxi` is only useful for reading or redeeming an existing mPST position: the node refuses a Maxi deposit even though the program would still accept one.

Yield [#yield]

**`getApy`**: the target base APY of the mode, read from the on-chain mode config, plus Huma's estimated Feathers rewards APY from the rewards API. Both come back in basis points (`baseApyBps`, `estRewardsApyBps`, `totalApyBps`) and in percent (`baseApyPercent`, `estRewardsApyPercent`, `totalApyPercent`). The rewards estimate exists for Classic only; Maxi reports zero there, because its rewards are Feathers rather than a USDC rate.

**`getTokenPrice`**: the current PST or mPST price in USDC, computed on chain as pool assets divided by token supply. `price` is a decimal string such as `1.034512` and `priceRaw` is the same figure in 6-decimal base units. `tokenMint`, `symbol`, and `underlyingMint` name the token and USDC.

**`getPoolStatus`**: the pool's liquidity and limits, read from its on-chain config and state accounts. No wallet is involved. `status` is `on`, `off`, `preClosure`, or `closed`, and `acceptingDeposits` is true while the pool is on with room under `liquidityCap` (`depositRoom` is that room). `poolUsdcOnHand` is the USDC sitting in the pool vault, `liquidAssetsDeployed` is what the pool has lent out but can recall, and `totalAssets` sums every mode. The instant-withdrawal fee is keyed to the pool's liquid-asset ratio after a withdrawal: `instantFeeTiers` lists each tier (fee in basis points while the ratio is below a threshold), `estimatedLiquidRatioPercent` is the ratio right now, and `estimatedInstantFeeBps` is the tier that ratio falls in. On mainnet in September 2026 the tiers were 3 bps above 12% liquidity, then 20 bps, 1%, 1.5%, 1.8%, and 100% below 5%. `instantReserveFloor` is USDC the pool keeps back from instant withdrawals. `redemptionWindow` and `instantWindow` report the program's daily caps on shares with today's usage and what remains. The estimate is informational: a dry run of `instantWithdraw` returns the exact fee the program computes.

Position [#position]

**`getBalances`**: the wallet's position in the mode. **Owner Wallet** is optional; leave it empty to read the connected wallet, or pass any base58 address (no signature is involved). The output splits the balance into `unlocked` (redeemable now), `locked` (inside a 3 or 6 month lockup, reported by Huma's rewards API), and `pendingRedemptions` (escrowed in open redemption requests, read from the Huma program's lender account on chain, with `pendingRequests` counting the open requests), plus `claimableUsdc` (processed USDC Huma could not transfer to the wallet and holds for you to claim; usually 0), `total` (unlocked plus locked), the current `price`, and `valueUsdc` (total times price). Every figure is a decimal string with a matching `...Raw` field in base units. A wallet that never held the token reads all zeros rather than failing. Lockups have no on-chain record, so `locked` depends on Huma's rewards API: when that read fails the node reports `locked` as 0, `unlocked` as the full held balance, and explains in `lockupReadWarning` instead of failing.

Wallet [#wallet]

**`deposit`** signs a live transaction. It builds the deposit with the SDK, verifies that the bytes carry exactly the requested amount, lockup, and mode mint and that your wallet is the only signer, checks the wallet's USDC and SOL, and then signs and broadcasts once.

* **Amount (USDC)** is in human units with at most 6 decimals: `25` is 25 USDC. The minimum is 1 USDC. Huma caps each wallet at 2,000,000 USDC across PST and mPST; the SDK refuses to build a deposit past it and the node reports that refusal.
* **Lockup** is optional: `none` (default, redeem any time), `3m` (2x Feathers), or `6m` (3x Feathers). A locked position cannot be withdrawn until its term ends, and transferring, swapping, or lending locked tokens forfeits the bonus retroactively. Lockups only move forward; a later deposit can extend one but never shorten it. Set a lockup deliberately, never as a default.
* With **Dry run** on (the default for a freshly placed node), the node returns `status: "simulated"` with `simulation.ok`, `simulation.error`, `simulation.unitsConsumed`, the estimated PST at the current price, and `balanceWarning` when the wallet is short. Nothing is signed. With it off, the output carries `signature`, `txExplorer`, and `status` of `confirmed` or `pending`.

**`requestWithdrawal`** signs a live transaction. It files a redemption request for **Amount** PST or mPST (human units, minimum 1). This is not an instant withdrawal: the tokens move out of the wallet into the request, and Huma pays out USDC when it processes the request. Requests are processed first-come first-served, typically within one business day with a seven day service level, under a daily global cap that resets at 00:00 UTC. Only the unlocked balance can be requested; the node reads the lockup figure from Huma's rewards API and refuses a request that exceeds it, and when that read is unavailable the node refuses to sign, because lockups have no on-chain record and the program cannot tell locked tokens from unlocked ones; the dry run still runs and explains the gap in `lockupReadWarning`. Once the transaction confirms, the node re-reads the lender account on chain and reports the new `pendingRedemptions` and `pendingRequests`. It also tells Huma's services about the request; `synced` reports whether that call succeeded, and a failed sync (for example for a wallet that has never signed in to app.huma.finance) never fails the run because Huma also scans the chain and the pending figure above comes from the chain regardless. For an instant exit, swap PST to USDC on Relay or Jupiter instead.

**`instantWithdraw`** signs a live transaction through the program's own instant-withdrawal path, which Huma's public documentation does not yet describe (Solaris AI verified it against the deployed program). It burns **Amount** PST (human units, minimum 0.01) and pays USDC into your wallet in the same transaction: the shares' value at NAV minus a fee. The fee is progressive across the liquid-asset-ratio tiers the withdrawal crosses, so it is 3 bps while the pool is liquid and climbs steeply when the pool is short; the pool pulls USDC back from its lending strategy (JupLend today) when its vault balance is not enough. **Max fee** is your ceiling in basis points of the USDC value (default 25): the node converts it to the absolute cap the program expects, and the program refuses the withdrawal when its fee would exceed that cap, so a low cap is the safety net against a stressed pool. Only the unlocked balance can be withdrawn; the node applies the same lockup check as `requestWithdrawal`. The dry run returns `assets` (USDC at NAV), `fee`, `feeBps`, and `netUsdc`, exactly as the program computed them, which makes it the quote to compare against a swap. A live run reads the same receipt from the landed transaction and reports `fromStrategy` when the pool had to recall lending liquidity. The withdrawal counts against its own daily cap (`instantWindow` in `getPoolStatus`), separate from the redemption queue.

**`claimProcessed`** collects USDC from redemption requests Huma already processed but could not transfer to your wallet at the time (the `claimableUsdc` figure from `getBalances`; usually zero, non-zero only when the payout transfer failed and the funds were parked for you). The node reads the chain first and returns `status: "nothing-to-claim"` without signing when nothing is waiting, so it is safe to run on a schedule. When something is waiting it signs the program's `disburse` instruction, which pays out everything at once; `claimed` reports the amount on a confirmed run.

Before signing any of these transactions, Solaris AI decodes what was built and refuses anything outside the expected shape: only the Huma program and the Associated Token program may appear, only your wallet may sign, any token account being created must be your own (or, for an instant withdrawal, the pool's receipt-token account that the lending pull needs), the deposit, redemption, or instant-withdrawal instruction must carry exactly the requested amount (plus the requested lockup on a deposit and the computed fee cap on an instant withdrawal), and the USDC must be paid to your own account. The signature and blockhash are saved before the first broadcast. The landing helper may resend the same signed bytes, but the engine never retries the operation with a new signature. A transaction still unconfirmed after the sixty-second landing budget is reported as `pending`; the next run reconciles that evidence against the chain before signing another transaction.

Configuration [#configuration]

| Field     | Type    | Required                                          | Description                                                                                         |
| --------- | ------- | ------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| mode      | string  | Yes                                               | `classic` (PST) \| `maxi` (mPST, retired: reads and `requestWithdrawal` only)                       |
| owner     | string  | No                                                | `getBalances` wallet to read instead of the connected wallet                                        |
| amount    | string  | `deposit`, `requestWithdrawal`, `instantWithdraw` | Human units, up to 6 decimals; at least 1 (0.01 for `instantWithdraw`); templates accepted          |
| lockup    | string  | No                                                | `deposit`: `none` (default) \| `3m` \| `6m`                                                         |
| maxFeeBps | string  | No                                                | `instantWithdraw`: fee ceiling in whole basis points, 1 to 10000, default 25                        |
| dryRun    | boolean | No                                                | `deposit`, `requestWithdrawal`, `instantWithdraw`, `claimProcessed`: build and simulate, never sign |

Output [#output]

Read operations return the standard envelope with the figures under `data`:

```json
{
  "success": true,
  "operation": "getBalances",
  "data": {
    "mode": "classic",
    "owner": "7fUAJdStEuGbc3sM84cKRL6yYaaSstxLsvvDvHtiQVEm",
    "tokenMint": "59obFNBzyTBGowrkif5uK7ojS58vsuWz3ZCvg6tfZAGw",
    "symbol": "PST",
    "unlocked": "250",
    "unlockedRaw": "250000000",
    "locked": "0",
    "lockedRaw": "0",
    "pendingRedemptions": "0",
    "pendingRedemptionsRaw": "0",
    "pendingRequests": "0",
    "claimableUsdc": "0",
    "claimableUsdcRaw": "0",
    "total": "250",
    "totalRaw": "250000000",
    "price": "1.034512",
    "valueUsdc": "258.628",
    "lockupReadWarning": null
  }
}
```

Reference fields downstream with the response name (default `humaResponse`), for example `{humaResponse.data.totalApyPercent}` after `getApy`, `{humaResponse.data.unlocked}` after `getBalances`, or `{humaResponse.data.signature}` after `deposit`.
