Liquidity-Provider Fee APR
Install and import#
npm install fintech-algorithmsimport { feeApr } from "fintech-algorithms/digital-assets-and-on-chain-finance/liquidity-and-liquidation/liquidity-provider-fee-apr";Signature#
feeApr(data, config)Sums attributable fee income over a daily ledger — volume × fee rate × LP share × (1 − protocol share) — divides it by time-weighted average LP capital, then scales the observed period linearly by annualization_days / elapsed_days. The annualisation is simple, not compounded. Impermanent loss, token-price P&L, incentive emissions, range uptime, gas and taxes are all outside this metric.
Parameters#
| Name | Type | Notes |
|---|---|---|
data | { rows: { timestamp?, duration_days?, volume, fee_rate, lp_share, lp_capital }[] } | A non-empty ledger of intervals. volume is nonnegative, fee_rate and lp_share are fractions in [0, 1], lp_capital is positive, and duration_days defaults to 1. timestamp is carried through to the trace and is not used in the arithmetic. |
config | { annualization_days?, protocol_fee_share?, capital_basis? } | annualization_days defaults to 365 and must be positive; protocol_fee_share defaults to 0 and lies in [0, 1]; capital_basis is time_weighted (the default) or ending. |
Returns#
{ elapsed_days, gross_volume, lp_fee_income, time_weighted_average_capital, capital_denominator, capital_basis, protocol_fee_share, simple_fee_apr, period_fee_return, annualization_days, trace }
The LP fee income and the capital denominator that produced simple_fee_apr, the unannualised period_fee_return, and a per-row trace carrying daily_fee_income, cumulative_fee_income and the running_apr recomputed over the prefix. All numbers are rounded to ten decimal places.
Errors#
- When data or config is not an object, or rows is missing or empty — throws
- When a row value is missing, non-finite, or outside its declared range — throws
- When annualization_days is not positive, or protocol_fee_share is outside [0, 1] — throws
- When capital_basis is neither time_weighted nor ending — throws
Complexity: time O(rows),
space O(rows).
Worked example#
executed Captured by running this function on the input its own test provides. Real output of real code — but not asserted against a published figure.
Input#
{
"rows": [
{
"timestamp": "2026-01-01T00:00:00Z",
"duration_days": 1,
"volume": 2500000,
"fee_rate": 0.003,
"lp_share": 0.02,
"lp_capital": 1000000
},
{
"timestamp": "2026-01-02T00:00:00Z",
"duration_days": 1,
"volume": 2738636.056514657,
"fee_rate": 0.003,
"lp_share": 0.02,
"lp_capital": 1000000
},
{
"timestamp": "2026-01-03T00:00:00Z",
"duration_days": 1,
"volume": 2930007.3153574164,
"fee_rate": 0.003,
"lp_share": 0.02,
"lp_capital": 1000000
}
]
}{
"annualization_days": 365,
"protocol_fee_share": 0,
"capital_basis": "time_weighted"
}Call#
feeApr(data, config)Returns#
object with 11 fields: elapsed_days, gross_volume, lp_fee_income, time_weighted_average_capital, capital_denominator, capital_basis, protocol_fee_share, simple_fee_apr, …
{
"elapsed_days": 365,
"gross_volume": 912500000,
"lp_fee_income": 54750,
"time_weighted_average_capital": 1000000,
"capital_denominator": 1000000,
"capital_basis": "time_weighted",
"protocol_fee_share": 0,
"simple_fee_apr": 0.05475,
"period_fee_return": 0.05475,
"annualization_days": 365,
"trace": [
{
"index": 0,
"timestamp": "2026-01-01T00:00:00Z",
"volume": 2500000,
"lp_capital": 1000000,
"daily_fee_income": 150,
"cumulative_fee_income": 150,
"running_apr": 0.05475
},
{
"index": 1,
"timestamp": "2026-01-02T00:00:00Z",
"volume": 2738636.056514657,
"lp_capital": 1000000,
"daily_fee_income": 164.3181633909,
"cumulative_fee_income": 314.3181633909,
"running_apr": 0.0573630648
},
{
"index": 2,
"timestamp": "2026-01-03T00:00:00Z",
"volume": 2930007.3153574164,
"lp_capital": 1000000,
"daily_fee_income": 175.8004389214,
"cumulative_fee_income": 490.1186023123,
"running_apr": 0.0596310966
}
]
}Other exports#
This module also exports
impermanentLoss, healthFactor, liquidationPrice, liquidationWaterfall, runTopic. Every module additionally exports run as an alias of its
primary function, and a meta object carrying its catalog id, domain, family,
shape and article URL.
Diagrams#
Calculation flow#
Liquidity-Provider Fee APR — Calculation and Decision Flow
flowchart LR
A["Identify protocol, version, chain, and valuation time"] --> B["Validate finite inputs and common units"]
B --> C["Attribute observed fees and annualize against capital-days"]
C --> D["Return value plus state/reason"]
D --> E["Check equality, zero, and unsupported states"]
E --> F["Compare sensitivity profiles"]
F --> G{"Operational evidence complete?"}
G -->|No| H["Keep as synthetic or descriptive calculation"]
G -->|Yes| I["Add live source, oracle, execution, and finality controls"]
How it works#
This page states the contract — how to call it correctly. The article explains the concept: why it works, and where it breaks.
References#
- Uniswap v2 Core — Uniswap; Hayden Adams, Noah Zinsmeister, and Dan Robinson
- Uniswap v3 Core — Uniswap; Hayden Adams, Noah Zinsmeister, Moody Salem, River Keefer, and Dan Robinson
- UniswapV3Pool.sol — Uniswap; Uniswap Labs and protocol contributors
- Evidence boundary