Then add this extra interest to the stored cumulativeInterestRate.
Important context
The current account choice appears to be correct:
position.collateralCustody
→ used for current cumulative interest / borrow fee calculation
position.custody
→ used for traded token mint lookup
Do not “fix” this by switching back to position.custody for borrow-fee calculation. That caused SHORT positions to become wildly wrong.
The current implementation is close for both LONG and SHORT positions, so the remaining problem is probably precision/freshness, not the wrong account.
Suggested implementation steps
Decode more fields from the Jupiter Perps custody account:
fundingRateState.cumulativeInterestRate
fundingRateState.lastUpdate
fundingRateState.hourlyFundingDbps
Add suitable ValueTags for the new decoded values, for example:
ΩJupiterLastUpdateTimestampΩ
ΩJupiterHourlyFundingDbpsΩ
Extend JupiterCustodyAccountInfo with the new fields.
Implement an effective cumulative interest calculation:
Use effectiveCumulativeInterestRate instead of raw cumulativeInterestRate when calculating borrowFeesDue.
Compare app output against Jupiter UI for at least:
SOL LONG
SOL SHORT
BTC LONG
BTC SHORT
ETH LONG
ETH SHORT
Acceptance criteria
borrowFeesDue still works for both LONG and SHORT positions.
The implementation still uses collateralCustodyAccountAddress for borrow-fee interest.
App values match Jupiter UI more closely than the current raw cumulativeInterestRate calculation.
The code remains compile-safe through ValueTags, so custody/traded-token lookup and collateral/borrow-fee lookup cannot easily be mixed up.
## Problem
This is a continuation from #22.
`borrowFeesDue` is currently calculated from:
* `custody.fundingRateState.cumulativeInterestRate`
* `position.cumulativeInterestSnapshot`
* `position.sizeUsd`
The formula currently used is approximately:
```java
positionInterest =
cumulativeInterestRate.subtract(cumulativeInterestSnapshot);
borrowFeesDue =
ceil(positionInterest * sizeUsd / RATE_POWER);
```
This is close to the Jupiter UI, but not always exact.
Example observed:
```text
App: 0.008150
UI: 0.00839
```
The values are close enough for now, but the app is slightly behind the UI.
## Likely cause
The current implementation uses the last stored on-chain `cumulativeInterestRate`.
Jupiter UI appears to calculate an effective/live cumulative interest value by adding the interest accrued since `fundingRateState.lastUpdate`.
So the more precise formula is likely:
```text
effectiveCumulativeInterest =
custody.fundingRateState.cumulativeInterestRate
+ current accrued funding/borrow interest since lastUpdate
```
Then:
```text
positionInterest =
effectiveCumulativeInterest - position.cumulativeInterestSnapshot
```
And finally:
```text
borrowFeesDue =
ceil(positionInterest * position.sizeUsd / RATE_POWER)
```
## Details to investigate
The custody account contains additional fields needed for the more precise calculation, likely under `fundingRateState`, including:
```text
cumulativeInterestRate
lastUpdate
hourlyFundingDbps
```
The more precise logic should check whether current Unix time is greater than `fundingRateState.lastUpdate`.
If so, calculate the extra accumulated interest since `lastUpdate`, probably something like:
```text
extraInterest =
currentFundingRate * (currentUnixTimestamp - lastUpdate) / 3600
```
Then add this extra interest to the stored `cumulativeInterestRate`.
## Important context
The current account choice appears to be correct:
```text
position.collateralCustody
→ used for current cumulative interest / borrow fee calculation
position.custody
→ used for traded token mint lookup
```
Do not “fix” this by switching back to `position.custody` for borrow-fee calculation. That caused SHORT positions to become wildly wrong.
The current implementation is close for both LONG and SHORT positions, so the remaining problem is probably precision/freshness, not the wrong account.
## Suggested implementation steps
1. Decode more fields from the Jupiter Perps custody account:
* `fundingRateState.cumulativeInterestRate`
* `fundingRateState.lastUpdate`
* `fundingRateState.hourlyFundingDbps`
2. Add suitable ValueTags for the new decoded values, for example:
* `ΩJupiterLastUpdateTimestampΩ`
* `ΩJupiterHourlyFundingDbpsΩ`
3. Extend `JupiterCustodyAccountInfo` with the new fields.
4. Implement an effective cumulative interest calculation:
```text
effectiveCumulativeInterestRate =
cumulativeInterestRate + accruedInterestSinceLastUpdate
```
5. Use `effectiveCumulativeInterestRate` instead of raw `cumulativeInterestRate` when calculating `borrowFeesDue`.
6. Compare app output against Jupiter UI for at least:
* SOL LONG
* SOL SHORT
* BTC LONG
* BTC SHORT
* ETH LONG
* ETH SHORT
## Acceptance criteria
* `borrowFeesDue` still works for both LONG and SHORT positions.
* The implementation still uses `collateralCustodyAccountAddress` for borrow-fee interest.
* App values match Jupiter UI more closely than the current raw `cumulativeInterestRate` calculation.
* The code remains compile-safe through ValueTags, so custody/traded-token lookup and collateral/borrow-fee lookup cannot easily be mixed up.
liquidationPrice now matches Jupiter UI closely after using collateralCustody for borrow fee calculation. Remaining mismatch appears to be caused by borrowFeesDue precision, likely because we do not yet include accrued interest since custody fundingRateState.lastUpdate.
liquidationPrice now matches Jupiter UI closely after using collateralCustody for borrow fee calculation. Remaining mismatch appears to be caused by borrowFeesDue precision, likely because we do not yet include accrued interest since custody fundingRateState.lastUpdate.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
This is a continuation from #22.
borrowFeesDueis currently calculated from:custody.fundingRateState.cumulativeInterestRateposition.cumulativeInterestSnapshotposition.sizeUsdThe formula currently used is approximately:
This is close to the Jupiter UI, but not always exact.
Example observed:
The values are close enough for now, but the app is slightly behind the UI.
Likely cause
The current implementation uses the last stored on-chain
cumulativeInterestRate.Jupiter UI appears to calculate an effective/live cumulative interest value by adding the interest accrued since
fundingRateState.lastUpdate.So the more precise formula is likely:
Then:
And finally:
Details to investigate
The custody account contains additional fields needed for the more precise calculation, likely under
fundingRateState, including:The more precise logic should check whether current Unix time is greater than
fundingRateState.lastUpdate.If so, calculate the extra accumulated interest since
lastUpdate, probably something like:Then add this extra interest to the stored
cumulativeInterestRate.Important context
The current account choice appears to be correct:
Do not “fix” this by switching back to
position.custodyfor borrow-fee calculation. That caused SHORT positions to become wildly wrong.The current implementation is close for both LONG and SHORT positions, so the remaining problem is probably precision/freshness, not the wrong account.
Suggested implementation steps
Decode more fields from the Jupiter Perps custody account:
fundingRateState.cumulativeInterestRatefundingRateState.lastUpdatefundingRateState.hourlyFundingDbpsAdd suitable ValueTags for the new decoded values, for example:
ΩJupiterLastUpdateTimestampΩΩJupiterHourlyFundingDbpsΩExtend
JupiterCustodyAccountInfowith the new fields.Implement an effective cumulative interest calculation:
Use
effectiveCumulativeInterestRateinstead of rawcumulativeInterestRatewhen calculatingborrowFeesDue.Compare app output against Jupiter UI for at least:
Acceptance criteria
borrowFeesDuestill works for both LONG and SHORT positions.collateralCustodyAccountAddressfor borrow-fee interest.cumulativeInterestRatecalculation.liquidationPrice now matches Jupiter UI closely after using collateralCustody for borrow fee calculation. Remaining mismatch appears to be caused by borrowFeesDue precision, likely because we do not yet include accrued interest since custody fundingRateState.lastUpdate.