Skip to main content
Every read in the SDK returns an entity: a typed class defined in @iris-credit/core-sdk whose derived values mirror the Iris contracts exactly. The math is framework-agnostic and runs offline: positions can be projected to arbitrary timestamps without an RPC; viem is only needed to hydrate entities from the chain.

Reading through the entity

The client.iris.core(chainId) entity exposes one getter per input a flow takes. Flows are fetch-first, so one fetch can feed several builds and a stale build never hides a fetch:
Every getter accepts optional FetchParameters (blockNumber, blockTag, stateOverride) for historical or state-overridden reads. getVenueData reads the venue as it stands for pod, so a venue the pod has not entered comes back holding nothing: the shape refinance expects of its target venue. pod defaults to the zero address, the pod-less view take expects, and a solver-signed Quote carries every other field, so a quote satisfies the params directly.
getPositionData reads the whole venue state. Prefer getLoanData for flows that only need the loan, and hand an AccrualPosition’s .loan to those flows instead of re-fetching.
Outside the entity, every fetcher is also exported standalone from @iris-credit/core-sdk (fetchLoan, fetchAccrualPosition, fetchVenue, fetchBlm, …), or, by importing @iris-credit/core-sdk/augment once, attached to each entity class as a fetch static:

Offline math

AccrualPosition carries the whole position model. Health, repay pricing and withdraw ceilings are plain property reads, and accrueLegs(timestamp) projects the position (venue indices included, using the venue’s own rate model) to any timestamp:
The timestamp can also sit in the future, and what projecting adds is the floating side: repayAmount is flat until maturity, so a closing cost needs no projection, while a future floatingLeg is the venue rate model’s estimate of the venue cost by that time, the number a solver nets against the fixed leg. Flat is not exact to the unit: the fixed total is settled as two separately rounded-down parts, the interest accrued to the settlement timestamp and the residual from there to maturity, so repayAmount can shift by one unit with that timestamp. Fund a repay with headroom rather than the figure read from the position, as repay and close do. Onchain operations are mirrored as pure transitions returning a new position (repay, liquidate, liquidateBond, supplyCollateral, withdrawCollateral, supplyBond, withdrawBond and refinance), each accruing and rebasing exactly as Iris does:
Accruing to a timestamp covers the clock, not the chain: the venue’s indices move with its own rate model, but the oracle price and any activity on the venue since the snapshot (which shifts its utilization, and with it the rate) only show up on a re-fetch. Health checked against an old price is silently off.
A recent snapshot accrued forward is fine for estimates. For results that must match Iris’s onchain numbers, read one block and pin every fetch and accrual to it. Composed reads (a position and a refinance target venue, a loan and its BLM) stay on one snapshot, and the block’s own timestamp beats the local clock, which does not follow the chain’s:

Venue rates and bounds

Venue also answers what the venue underneath would accept right now. Each answer is computed with that venue’s own validation math rather than from the normalised view, so an amount at the bound clears the venue’s checks and one wei more does not:
Each bound takes an optional timestamp and accrues the venue to it first; getMaxBorrowAmount takes its options as an object, { maxLtv, timestamp }, where maxLtv (WAD-scaled) defaults to, and is capped by, the venue’s own max borrow LTV, so a caller can tighten the bound but never exceed the venue’s. It folds getMaxBorrowCapacity in, so a paused, frozen or dry venue answers 0n rather than an amount the venue would reject. On Morpho Blue, getMaxBorrowCapacity takes an optional target utilisation as a second argument, and getMaxSupplyCapacity is unbounded. A bound reads undefined rather than a number when its inputs are missing: on Morpho Blue when the venue price is unknown, on Aave V3 when the venue was constructed by hand instead of fetched, since the Aave bounds read reserve state that the fetchers hydrate. borrowApy is the rate the venue quotes at the snapshot’s timestamp. On Morpho Blue, getBorrowApy(timestamp) projects the Adaptive Curve IRM’s adaptation forward to a later one, and an idle market (zero IRM) reads 0n, matching its zero-rate accrual. A market on any other interest-rate model throws UnsupportedVenueIrmError from both, and from any accrual to a later timestamp while the market has debt, rather than projecting it at a zero rate. Aave V3’s rate only moves when the reserve is touched, so there is nothing to project.
ltv is not lltv. lltv is the liquidation threshold an open position is measured against; ltv is the limit new debt is checked against at borrow time. On Aave V3 the two differ, and sizing a borrow against lltv overshoots what the venue accepts. On Morpho Blue they are the same value.

Units & precision

The SDK follows the same conventions as the Iris API:
  • Rates, LLTVs and fees are WAD-scaled (1e18). A fixedRate of 81000000000000000n is 8.1% simple annual interest.
  • Amounts are in the token’s own decimals. Read decimals off a fetched Token.
  • Everything is bigint. No floats anywhere; format for display with @iris-credit/iris-ts’s format helpers.
The contracts store rates and LLTVs BP-compressed (1e14) to fit small integer slots. The fetchers rescale them to WAD on the way in; only a raw Iris.getLoan call returns the compressed values.

Protocol constants

The bounds and parameters Iris enforces ship as exported constants, so quoting and validation never hardcode them:
These are the immutable contract’s own parameters, mirrored from its ConstantsLib, so they change only with a protocol redeployment.

Bond requirements

Blm computes the bond a quote requires without a bondRequirement contract call:
A requirement of zero is an unsubmittable quote, so bondRequirement throws IrisCoreErrors.ZeroBondRequirement instead of returning 0n. Two cases reach it: the BLM has no parameters set for the debt token, or the debt is small enough that the requirement rounds down to zero. Both are quoting-time conditions, so catch the error and drop the quote rather than returning terms no borrower can open.
This is the BLM’s requirement for a prospective quote, not position.bondRequirement, which is the requirement recorded on an open loan and legitimately reads 0n once that loan is resolved.

Addresses & registries

Two static, per-chain sources ship with the SDK, both narrowed to the exact chain by their getter:
  • getChainAddresses(chainId) holds what is deployed: the Iris core, BLMs, bundler adapters, venue adapters and common tokens.
  • getChainRegistry(chainId) holds what is enabled on the Iris contract: venue ids, accepted bond LLTVs, and the market data payloads. The contract only stores keccak256(data), so each payload is recorded as a preimage keyed by that enabled hash, which for a Morpho Blue payload is the Morpho market id.
getMarketData matches the hash case-insensitively and throws UnknownDataHashError when the chain’s registry does not record it (a payload enabled after the SDK release, for instance). Indexing marketDatas directly still works, but its keys are exact literals, so a hash only known at runtime has to go through the getter. Enablement is append-only onchain, so registry entries can only ever be stale-incomplete, never stale-wrong. Solvers can quote from the registry offline, while the fetchers re-verify mutable state (BLM params, whitelist entries, fee) at runtime. The pairs, venues and Morpho markets behind these entries are listed in Supported markets.
Both sources are compile-time constants: supporting a new chain means a new SDK release. Fetchers that resolve a contract from the registry throw UnsupportedChainIdError on an unknown chain.

EIP-712 payloads

The signature builders return typed data ready for viem’s signTypedData, the same payloads Iris verifies onchain:
  • getQuoteTypedData(chainId, quote): a solver’s Quote, consumed by take
  • getAuthorizationTypedData(chainId, authorization): granting or revoking a manager on Iris
  • getPermitTypedData(args, chainId): an ERC-2612 permit, taking its EIP-712 domain version from the per-chain SIMPLE_PERMIT_TOKENS allowlist and falling back to the "1" most ERC-2612 tokens sign
  • getPermit2PermitTypedData(args, chainId): a Permit2 allowance (PermitSingle), clamping allowance to uint160, the width of PermitDetails.amount
  • getPermit2TransferFromTypedData(args, chainId): a Permit2 signature transfer (PermitTransferFrom), clamping allowance to uint256, the width of TokenPermissions.amount
Most integrations never touch these directly: transaction flows collect signatures through their requirements, and signResponse wraps the solver side.