NashPoint
NashPoint
  • Introduction
    • Introduction To Nashpoint
    • Current Features & Capabilities
    • Post Launch Roadmap
  • User Documentation
    • Node Contract Overview
    • Node Owner & Rebalancer Roles
    • Portfolio Management
    • Rebalancing & Strategy Execution
    • User Deposits & Shares
    • Asynchronous Redemptions
      • Two Step Process
    • Swing Pricing
    • Processing User Redemptions
    • Management & Execution Fees
  • Developer Documentation
    • Overview
    • Role-Based Access Control
    • Smart Contract Architecture
  • Routers
    • ERC-4626 Router
    • ERC-7540 Router
    • Router Tolerance
  • Creating A Node
  • Asynchronous Redemptions
  • Managing a Node
    • Adding & Removing Components
    • Updating Component Allocations
    • Rebalance Window & Cooldown
    • Rebalancing a Node
    • Managing Rebalancers
    • Processing User Redemptions
      • Reserve vs Component Fulfillment
    • Reserve Management
    • Fees Configuration
    • Liquidation Queue Configuration
    • Max Deposit Limits
    • Operator Permissions
    • Emergency Controls
  • Upgrading a Node
    • Adding Quoters & Routers
    • Custom Router Development
    • Multi-Tier Permissioning
  • Cached Data & Gas Efficiency
  • Swing Pricing Calculations
  • Adding Routers and Components - Step by Step Guide
  • Node Execute Function
  • Resources
    • FAQ
    • Glossary
    • Supported Networks & Protocols
    • Deployments
    • Audits
    • GitHub
    • Telegram
    • NashPoint
  • Node Strategies
    • Test Node A
Powered by GitBook
On this page
  • Swing Pricing
  • Swing Pricing in Node Contract
  • Node and Quoter Interaction
  • QuoterV1 Functions
Edit on GitHub

Swing Pricing Calculations

Swing Pricing

Swing pricing adjusts share price to maintain healthy reserve levels by incentivizing deposits when reserves are low and penalizing withdrawals that would deplete reserves.

Core Mechanism

  • Each Node has a targetReserveRatio (e.g., 10%)

  • When reserves fall below target:

    • Withdrawals receive progressively worse pricing (up to maxSwingFactor)

    • Deposits receive bonus shares (up to maxSwingFactor/2)

  • Pricing adjusts exponentially based on distance from target ratio

Swing Pricing in Node Contract

Enable/Disable Swing Pricing

Node owner can enable swing pricing and set the maximum factor. Factor cannot exceed protocol maximum.

function enableSwingPricing(bool status_, uint64 maxSwingFactor_) external onlyOwner {
    if (maxSwingFactor_ > INodeRegistry(registry).protocolMaxSwingFactor()) revert ErrorsLib.InvalidSwingFactor();
    swingPricingEnabled = status_;
    maxSwingFactor = maxSwingFactor_;
    emit EventsLib.SwingPricingStatusUpdated(status_, maxSwingFactor_);
}

Share Price Calculation

Used during deposits to determine shares to mint. Applies bonus when reserves are below target.

function _calculateSharesAfterSwingPricing(uint256 assets) internal view returns (uint256 shares) {
    if ((totalAssets() == 0 && totalSupply() == 0) || (!swingPricingEnabled)
        || (MathLib.mulDiv(getCashAfterRedemptions(), WAD, totalAssets()) >= targetReserveRatio)) {
        shares = convertToShares(assets);
    } else {
        shares = quoter.calculateDepositBonus(
            assets, getCashAfterRedemptions(), totalAssets(), maxSwingFactor, targetReserveRatio
        );
    }
}

Redemption Price Calculation

Applied when users request redemptions. Reduces assets returned when reserves are low.

function requestRedeem(uint256 shares, address controller, address owner) external returns (uint256) {
    // ... other checks ...
    if (swingPricingEnabled) {
        uint256 adjustedAssets = quoter.calculateRedeemPenalty(
            shares, getCashAfterRedemptions(), totalAssets(), maxSwingFactor, targetReserveRatio
        );
        adjustedShares = MathLib.min(convertToShares(adjustedAssets), shares);
    }
    // ... rest of function ...
}

Reserve Status Check

Returns available reserve after accounting for pending redemptions.

function getCashAfterRedemptions() public view returns (uint256) {
    uint256 balance = IERC20(asset).balanceOf(address(this));
    uint256 exitingAssets = convertToAssets(sharesExiting);
    return balance >= exitingAssets ? balance - exitingAssets : 0;
}

Node and Quoter Interaction

The Node delegates all swing pricing calculations to its Quoter to keep pricing logic upgradeable. When a user deposits or requests a redemption, the Node checks if swing pricing is enabled and reserves are below target. If so, it calls the Quoter with current Node state (reserves, total assets, target ratio) and configured maxSwingFactor. The Quoter returns adjusted values that either increase shares for helpful deposits or decrease assets for harmful withdrawals.

QuoterV1 Functions

External Functions

Calculates bonus shares for deposits when reserves are low:

function calculateDepositBonus(
    uint256 assets,
    uint256 reserveCash,
    uint256 totalAssets,
    uint64 maxSwingFactor,
    uint64 targetReserveRatio
) external view returns (uint256 shares)
  • Takes deposit amount and Node state

  • Returns increased shares based on how much deposit helps restore reserve ratio

  • MaxSwingFactor is halved for deposits vs withdrawals

Calculates penalty for withdrawals that would reduce reserves:

function calculateRedeemPenalty(
    uint256 shares,
    uint256 reserveCash,
    uint256 totalAssets,
    uint64 maxSwingFactor,
    uint64 targetReserveRatio
) external view returns (uint256 assets)
  • Takes shares to redeem and Node state

  • Returns reduced assets based on impact to reserve ratio

  • Full maxSwingFactor can be applied

Internal Functions

Calculates how much a deposit helps restore reserve ratio:

function _calculateReserveImpact(
    uint64 targetReserveRatio,
    uint256 reserveCash,
    uint256 totalAssets,
    uint256 deposit
) internal pure returns (int256)
  • Calculates shortfall from target reserve

  • Returns percentage of shortfall that deposit closes

  • Lower return = higher bonus (inverse relationship)

Calculates actual swing factor to apply:

function _getSwingFactor(
    int256 reserveImpact,
    uint64 maxSwingFactor,
    uint64 targetReserveRatio
) internal pure returns (uint256)
  • Uses exponential curve based on reserve impact

  • Scales from 0 to maxSwingFactor

  • Returns 0 if reserves exceed target

  • Uses formula: maxSwingFactor * exp(SCALING_FACTOR * reserveImpact / targetReserveRatio)

PreviousCached Data & Gas EfficiencyNextAdding Routers and Components - Step by Step Guide

Last updated 2 months ago