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

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, falling back to the fresh projected index if no snapshot exists (prevents a stale view from masking settlements).

  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".

  • After swap.settled == true, this function returns (0, <buyerOwes>) (the internal branch that would compute a net only runs when !settled), so it is not a way to retrieve historical settlement amounts. Use settlementPayouts[swapId] for that.

See also: getFreshSwapNetAmount, settlementPayouts.


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

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 E606 / oracle-related errors if the base rate oracle is unhealthy.

See also: totalLPAvailableCollateral, buySwap.


updateMarketRateIndex

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

What it does: looks up market.referenceRateOracle, then calls rateIndex.update(oracle), 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 (minus the nested dynamic arrays, which are not included by the auto-getter). 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 13-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 transferred to the buyer's side for swapId (the amount credited via safeTransfer or moved to escrowedCollateral if the direct transfer failed). 0 means either the swap hasn't been settled yet or the buyer received nothing at settlement (e.g., lost the P&L and was not due a residual).

Paired with escrowedCollateral, this is how integrators read post-settlement entitlement without needing balance-diff accounting. SwapPositionWrapper uses exactly this pattern.

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