For the complete documentation index, see llms.txt. This page is also available as Markdown.

Views

Read-only paths into SwapCore, plus the one helper that exists only to refresh the oracle index for consumers who want a guaranteed-fresh read. Everything on this page is safe for off-chain consumers (frontends, indexers) to call via staticCall, with the one documented exception.

Source: SwapCore.sol (most entries) and lib/Views.sol (the getCalculatedAvailableLiquidity helper).

Why two flavors of P&L reads?

SwapCore stores a cumulative rate index per oracle (rateIndex) that is only written when a state-changing function runs — buySwap, supplyCollateral, withdrawCollateral, makePayment, exitSwapEarly, liquidateSwap, or the dedicated updateMarketRateIndex. Between those updates, a pure view read (getSwapNetAmount) projects a fresh index on the fly (via getFreshIndex) so the answer still reflects time elapsed since the last write. For consumers who want the stored index actually written to storage first, getFreshSwapNetAmount runs the update as a side effect, then returns the value — useful when a frontend wants to staticCall a mutable function and know the same number would be used by a subsequent makePayment.

See also updateMarketRateIndex for the standalone index-refresh path.


getSwapNetAmount

function getSwapNetAmount(bytes32 swapId)
    public view returns (uint256 netAmount, uint8 netRecipient);

Who calls: anyone. Pure view.

What it does: computes the current net payment obligation of an open swap — how much one side would owe the other if it settled right now. Projects the reference rate oracle forward with getFreshIndex (no state mutation) to account for time elapsed since the last index write, then runs the same fixed/floating payment math that makePayment uses at actual settlement.

Steps:

  1. Load the swap and market. Revert if the swap doesn't exist (E500) or the market is gone (E300).

  2. Compute timeElapsed, capped at swapTerm. If no time has elapsed (entryTimestamp == block.timestamp), return (0, 1) — no obligation, buyer is the trivial recipient.

  3. Resolve the effective oracle index:

    • Active swap: use getFreshIndex(oracle) — a projected-forward read.

    • Expired swap: use the snapshot written at expiryTimestamp via rateIndex.getIndexAt; if no snapshot exists yet, fall back to getIndexAtVirtual — which projects a fresh index at block.timestamp and interpolates it back to expiryTimestamp (matching what settlement would resolve, so a stale view can't mask a pending settlement).

  4. Derive floatingPaymentRate from (entryFloatingIndex, effectiveIndex, rateDuration) using SwapFormulas.deriveRateFromIndex.

  5. Compute fixedPayment and floatingPayment via SwapFormulas.calculateSwapPayment. For BUY_FLOATING, utilFee and riskPremium are added to the floating leg; for BUY_FIXED, fees are already baked into swap.swapRate.

  6. Net them with SwapFormulas.calculateNetObligation(fixedPayment, floatingPayment). Flip the buyerOwes bit if this is a BUY_FLOATING market (the buyer's side of the swap is the floating leg, not the fixed one).

  7. Cap by collateral. If the buyer is the one receiving, the net is capped at swap.poolCollateralBacking. If the buyer is the one paying, it's capped at swap.collateralBalance. This mirrors exactly what makePayment and liquidateSwap would do.

Returns:

Field
Meaning

netAmount

The net obligation in swapToken decimals. Always non-negative.

netRecipient

0 = LP pool receives, 1 = buyer receives.

Reverts:

Code
Reason

E500

Swap doesn't exist.

E300

Market doesn't exist (swap references a purged market — shouldn't happen in normal operation).

E606

Reference rate oracle returned invalid data during getFreshIndex.

Notes:

  • Returns (0, 1) for a swap where block.timestamp == entryTimestamp — useful sentinel for "just-opened".

  • Both return fields are only meaningful while the swap is open. Once swap.settled == true, the net-computing branch is skipped, so this function returns the sentinel (0, 1)netAmount defaults to 0 and netRecipient defaults to 1 ("buyer receives") regardless of who actually won. Do not read either field on a settled swap. To recover settlement data after the fact:

    • Direction + net amount (who received the net, and how much) → the SwapClosed event's netRecipient and amountSettled fields (emitted by every closure path; also returned synchronously as SettlementResult from makePayment / exitSwapEarly). There is no storage getter for netRecipient — it lives only in the event/return.

    • The buyer's total payoutsettlementPayouts[swapId] (plus escrowedCollateral[swapId] if the buyer-side transfer failed). Note this is the buyer's credited amount — returned collateral plus any winnings, or 0 if the buyer lost everything or was liquidated — not the net obligation and not a direction flag. A losing buyer can still have settlementPayouts > 0, so you can't infer netRecipient from it.

See also: getFreshSwapNetAmount, settlementPayouts, and the SwapClosed event for post-settlement direction and net amount.


getFreshSwapNetAmount

Who calls: frontends via eth_call / staticCall. Not marked view — this function mutates the global rate index.

What it does:

  1. Reads swap.marketId.

  2. Calls rateIndex.update(market.referenceRateOracle) — a real storage write under normal execution.

  3. Delegates to getSwapNetAmount(swapId).

The only reason this exists is so a frontend can staticCall a mutable function and receive the exact number makePayment would use in the next block, with zero divergence from the stored index. When called via staticCall, the index update is rolled back at the end of the simulation, so consumers get the fresh number without persisting the write.

⚠️ Do NOT call this on-chain. Every call performs a rateIndex.update, which is wasted gas if you're already about to call a state-changing function (that function will update the index itself). On-chain callers should use getSwapNetAmount directly.

Returns: same as getSwapNetAmount.

Reverts: same as getSwapNetAmount, plus any revert from rateIndex.update (which itself reverts with E606 if the oracle is unhealthy).

See also: getSwapNetAmount, updateMarketRateIndex.


getCalculatedAvailableLiquidity

Deployed on the Views helper contract, not SwapCore. Call it against the Views address.

Who calls: anyone.

What it does: returns the maximum notional a new swap can use right now, given the pool's unlocked collateral and the current base rate. Computed as:

In effect: "how much notional can this pool safely back, given that each notional unit consumes |baseRate| × swapTerm × leverageMultiplier worth of collateral for worst-case LP exposure?"

Use this to size the notionalAmount you pass to buySwap. If notionalAmount > getCalculatedAvailableLiquidity(marketId) at tx execution time, buySwap reverts via Utils.validateSwapParams. Because base rates move, quote-time and execute-time values can differ slightly — if that matters, pair it with buySwap's rateBound slippage guard.

Reverts: can revert with E611 / oracle-related errors if the base rate oracle is unhealthy.

See also: totalLPAvailableCollateral, buySwap.


getLpVestState

Deployed on the Views helper contract, not SwapCore. Call it against the Views address.

Who calls: anyone — primarily frontends that want to warn an LP about the profit-vest cap before they supply or withdraw.

What it does: reports the LP's current profit-vest state for a market. Reads the LP's position via SwapCore.getLpPosition, then returns the vest anchor, the window end, and whether the cap is currently binding:

  • entryPrice — the profit-vest anchor (share price recorded at the deposit that began the current vest window), WAD.

  • vestEndTimestamp — unix seconds; the cap applies while block.timestamp < vestEndTimestamp.

  • capActivetrue iff block.timestamp < vestEndTimestamp && getPoolSharePrice(marketId) > entryPrice. When true, a withdrawCollateral right now would burn shares at entryPrice rather than the live (higher) price.

For a fully-exited position (shares == 0), returns (0, 0, false) — stale anchor storage is ignored. See Liquidity provision → Profit-vest cap for the full mechanism.

Reverts: E300 if the market doesn't exist (propagated from SwapCore.getLpPosition).

See also: getLpValue (applies the cap to return the true redeemable amount), withdrawCollateral.


updateMarketRateIndex

Who calls: anyone — typically a keeper, but there's no gate.

What it does: first best-effort pokes any of the market's oracles (referenceRateOracle, baseSwapRateOracle, riskPremiumOracle) that advertised IPokeable at market creation — refreshing their internal state (e.g. TWAR buffers) so the index snapshot reflects the freshest values. Pokes are de-duplicated per oracle per block and are best-effort (they don't revert the call). It then calls rateIndex.update(market.referenceRateOracle), writing a fresh cumulative index entry keyed by block.timestamp. Used to:

  • Force an index snapshot at a specific timestamp (useful when a market has been quiet for a while and a keeper wants to refresh before heavy read activity).

  • Pre-update the index immediately before batch settlement so makePayment doesn't re-read the oracle for every swap in the batch — though makePayment already does this per-call, so it's rarely necessary.

Under normal operation every state-changing function already updates the index, so you typically don't need to call updateMarketRateIndex directly.

Reverts:

Code
Reason

E300

Market doesn't exist.

E606

Oracle returned invalid data during the update.

See also: getFreshSwapNetAmount, getPoolSharePrice.


State-variable getters

SwapCore exposes several public mappings and arrays. Solidity auto-generates a getter for each; these are the ones integrators most commonly read.

markets

Returns the full Types.Market struct. Market has no mappings or dynamic arrays, so the auto-getter returns every field, including the nested Pool sub-struct (totalShares, totalCollateral, lockedCollateral). Use this for market-config reads: oracles, pool (shares/collateral/locked), fee-curve parameters, earlyExitAllowed, earlyExitFee, liquidationIncentive, terminated, marketOwner, lpWhitelistEnabled, minCollateral, bucketInterval, riskPremiumOracle, numBuckets.

Non-existent markets return the zero-initialized struct with exists = false. Check .exists before treating the response as live data.

swapPositions

Returns the 14-field Types.SwapPosition tuple:

A swapId that doesn't exist returns all zeros — check entryTimestamp != 0 to confirm the swap is real.

settlementPayouts

After settlement, records the amount actually transferred to the buyer for swapId (buyerCollateralReleased). If the buyer-side transfer fails and the payout is escrowed instead, this slot is set to 0 and the amount is recorded in escrowedCollateral — the two are mutually exclusive, never double-counted. So 0 means one of: the swap isn't settled yet, the buyer was due nothing (lost the P&L / was liquidated), or the payout failed to transfer and is now sitting in escrow.

Because of that last case, integrators should read post-settlement entitlement as settlementPayouts[swapId] + escrowedCollateral[swapId], not settlementPayouts alone — exactly the sum exitSwapEarly uses for its slippage check, and the pattern SwapPositionWrapper follows.

escrowedCollateral

Non-zero when a buyer-side settlement or liquidation transfer failed (usually because the recipient became unable to receive the token). The balance is held until the buyer (or an authorized delegate) calls claimEscrow. Funds are earmarked to the original swap.userAddress — no one can redirect them. If the recipient is still blocked, the claimEscrow transfer reverts and the escrow stays in place.

isAuthorized

See Authorization. Returns true only for explicitly-set delegations; the implicit self-path (msg.sender == onBehalfOf) is not stored in this mapping, so code that mirrors SwapCore's auth rule should check operator == owner || isAuthorized[owner][operator].

marketLpWhitelist

Returns whether an address is whitelisted to supply LP collateral in a specific market. Only meaningful when markets[marketId].lpWhitelistEnabled == true. The market creator is auto-whitelisted at createMarket time.

pendingMarketOwner

Address that has been designated as the new owner of marketId but has not yet accepted via acceptMarketOwnership. address(0) if no transfer is in flight.

allMarketIds (array)

Positional read by index. Use getAllMarketIds() to fetch the whole array at once.

buckets

Aggregated swap data for (marketId, bucketId):

This is mostly of interest to offline analysts rebuilding the share-price calculation. For ordinary consumers, getPoolSharePrice is the right read.

Last updated