Our synthetic staking calculation pays 1200 reward tokens per year against a position worth 24000 reward tokens. The annual rate is five percent. Replacing the liquidity reserve with an unrelated reward budget makes the same interface display forty percent even though the emission rate has not changed.
We build the example using the accounting shape of a constant product AMM and a separate staking pool. All balances are synthetic. This is a calculation about units and denominators and supplies no forecast of token prices or future investment returns.
Convert LP ownership into a position value
The fixture's AMM has 1200 LP tokens outstanding and the staking pool holds 300 of them. Its ownership fraction is one quarter. The AMM reserve on the reward token side contains 48000 tokens so the staked LP represents 12000 tokens on that side.
We assume the second reserve has equal value when expressed in reward token units. Under that explicit assumption the total staked position is worth twice the represented reward reserve or 24000 reward tokens. This assumption is a valuation choice and does not turn a manipulated spot reserve into an independent market price.
function aprBasisPoints(annualRewards, reserve, stakedLp, totalLp) {
if (reserve <= 0n || totalLp <= 0n || stakedLp <= 0n)
throw new Error("missing denominator");
const positionValue = (2n * reserve * stakedLp) / totalLp;
if (positionValue === 0n) throw new Error("rounded denominator");
return (annualRewards * 10000n) / positionValue;
}A staking reward budget describes how much reward inventory a distributor holds. It does not measure the reserve backing an LP token. The two quantities can coincidentally have similar magnitudes which makes a bad denominator difficult to detect from a screenshot of the final percentage.
Keep raw decimal scales attached
Our reward asset uses six decimal places and the LP token uses eighteen. Solidity and ethers return raw integers. Applying an eighteen decimal formatter to both quantities changes the relative scale before the calculation even reaches the valuation formula.
We use BigInt to keep the ownership fraction as a multiplication followed by division. The eighteen decimal factors cancel between staked LP and total LP supply. The numerator and denominator of the final rate both remain expressed in raw reward token units so their six decimal factors cancel too.
We preserve the raw quantities until the final percentage conversion because a premature conversion to JavaScript Number can erase low order integer precision and a premature decimal formatting step can make a value look readable while silently changing the unit that the next multiplication expects to receive.
The fixture reports basis points to avoid floating point rounding. Five hundred basis points means five percent and the comparison calculation returns four thousand basis points. Display rounding belongs after the rate has been calculated using compatible quantities.
Annualize a rate using its actual clock
We begin with a declared annual reward quantity so the example isolates the denominator. A real distributor may expose rewards per second or per block. Per second emissions multiply by the chosen seconds per year. Per block emissions require an explicit block frequency assumption that changes when chain behavior changes.
The displayed rate is a current simple annualization. It does not model compounding or reward reinvestment. Calling that figure APY introduces another model because reinvestment frequency and execution costs affect compounded returns.
Reserve denominator: 500 basis points; budget denominator: 4000
6 assertions passedThe fixture also rejects a zero LP supply and a zero reserve. An empty pool supports no finite position valuation under this formula. Returning zero percent for an unavailable denominator confuses a missing measurement with a measured absence of rewards.
Test the formula by changing one input
If the staked LP quantity doubles while emissions remain fixed the represented position value doubles and the rate halves. If total LP supply doubles while reserves and staked quantity remain fixed the represented position shrinks and the rate doubles. These direction checks catch swapped inputs without needing a live chain.
For an ethers interface we read reserves and LP supply from a coherent block context. Values fetched across different blocks may describe different pool states. The UI should retain the measurement context and distinguish an unavailable read from an actual zero balance.
An independent price source gives the reserve valuation assumption something to compare against. Keep both calculations beside the same emission quantity so a changing percentage can be attributed to the denominator or the reward schedule without conflating them.