fix(utils): apply the min deposit rate to interest calculations - #38
Open
pucedoteth wants to merge 1 commit into
Open
pucedoteth wants to merge 1 commit into
pucedoteth wants to merge 1 commit into
Conversation
`min_deposit_rate_x18` is parsed into SpotProductConfig and then never read.
Neither calc_borrow_rate_in_period nor calc_deposit_rate_in_period applies it,
so both under-report against the engine.
SpotEngine._updateState converts the rate to a per-second figure, compounds it
over dt, and multiplies the result into both the borrow and the deposit
multiplier:
minDepositRatePerSecondX18 = minDepositRateX18 / 31536000
minDepositRateMultiplierX18 = (ONE + minDepositRatePerSecondX18).pow(dt)
cumulativeBorrowsMultiplierX18 *= minDepositRateMultiplierX18
cumulativeDepositsMultiplierX18 *= minDepositRateMultiplierX18
With a 5% min deposit rate, an hour of borrowing came out at 3.995e-06 against
the engine's 9.703e-06, and a day at 9.590e-05 against 2.329e-04.
calc_deposit_rate_in_period also returns 0 when nothing is borrowed. Zero
utilization only zeroes the borrower rate on chain; the min deposit multiplier
is applied either way, so depositors earn the floor on an idle pool.
The rate is read from product.config, which the calculation already receives,
so no signature changes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
min_deposit_rate_x18is parsed intoSpotProductConfig:and then never read anywhere in the SDK. Neither
calc_borrow_rate_in_periodnorcalc_deposit_rate_in_periodapplies it, so both under-report against what the engine actually accrues.SpotEngine._updateStateconverts the rate to a per-second figure, compounds it overdt, and multiplies the result into both multipliers:With a 5% min deposit rate, a 3.5% borrow curve and 50% utilization:
The same problem on the deposit side
calc_deposit_rate_in_periodreturns0when nothing is borrowed:On chain, zero utilization only zeroes the borrower rate —
borrowerRateX18 = 0. TheminDepositRateblock runs regardless and multiplies the deposit multiplier, so depositors still earn the floor while the pool is idle, which is the purpose of a rate floor.The fix
calc_min_deposit_rate_multiplierreproduces the engine'sminDepositRateMultiplier, and both functions apply it multiplicatively the way_updateStatedoes.The rate is read from
product.config, which these functions already receive — the same waycalc_borrow_rate_per_secondalready readsinterest_floor_x18and friends — so there are no signature changes and nothing downstream breaks._calc_borrow_multiplierwas split out because the deposit rate is derived from the engine'sborrowRateMultiplierbefore the min deposit multiplier is applied; reusingcalc_borrow_rate_in_periodthere would apply the floor twice.Companion change
The TypeScript SDK has the mirror image of this bug — it adds the annual rate to the period rate instead of omitting it, so it over-reports where this one under-reports. That is nadohq/nado-typescript-sdk#452. After both, the two SDKs agree with the engine and with each other.
Test plan
tests/utils/test_interest.pyadds 7 cases pinned to the engine's formula rather than to current output, across an hour, a day, 30 days and a year, plus the idle-pool deposit case.Reverting only
interest.pyand keeping the tests fails with the table above:ruff checkreportsI001(unsorted import block) onnado_protocol/utils/interest.py, but it does so on a clean checkout too — the import block is untouched here, so I left it rather than mixing an unrelated reorder into this diff.