-
Notifications
You must be signed in to change notification settings - Fork 139
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FxPool rounding errors fixes #393
FxPool rounding errors fixes #393
Conversation
…to match the contreact exactly
…to only 18 decimals
…n case of an exception in FXPool functions
…xpectedSpotPriceBeforeSwap` value are not precisely equal to the excel spreadsheet; all the tests that fail now, fail because of `expectedSpotPriceAfterSwap` - will need to check with Khidir about this;
src/pools/xaveFxPool/fxPool.ts
Outdated
const maxLimit = (1 + alphaValue) * parsedReserves._oGLiq * 0.5; | ||
const maxLimit = alphaValue | ||
.plus(1) | ||
.times(parsedReserves._oGLiq) | ||
.times(0.5); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @andreiashu 👋
I'm reviewing the PR over here and I realized you're updating from number
to bignumber.js
, but still using float points
.
Do you think it's possible to move to ethers BigNumber
or bigint
and update the code to use fixed point
math?
I ask that because that's what we're going to use on our new SOR version to keep consistency.
I know this would require a bigger change, but it would help a lot to migrate things later on.
Let me know if that makes sense or if you have any questions!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hi @brunoguerios, I appreciate you looking over this PR!
I just pushed a commit whereby we now pass the floats as strings to OldBigNumber
.
re moving to ethers BigNumber
or bigint
: you mean that, ideally, we shouldn't be using OldBigNumber
anymore and just stick with Ethers BigNumber
?
re fixed point math
: can you give me an example as to how you're approaching this in the new version of SOR? We're using ABDKMath64x64.sol in our contracts, and 36 decimals seemed to be enough precision on the SOR side for us (see _inHigherPrecision and parseFixedCurveParam ). We have several places where we round (down) to a specific number of decimals depending on the number of decimals that is expected (see viewRawAmount and viewNumeraireAmount). This part was somewhat more challenging to fix in the SOR code. In our smart contracts, converting from wei to fixed point 64x64 happens several times throughout the lifecycle of a swap. Each conversion operation has its own precision loss that ultimately was compounding to higher values of loss in total in our SOR code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure thing! Thanks for getting back to me with more context! 😊
Yes, moving from OldBigNumber
to either ethers BigNumber
or bigint
would be the ideal solution, because it forces you to use fixed point
instead of float point
.
This is how that maxLimit
calculation would look like in fixed point math:
const alphaFixed = parseFixed(alphaValue.toString(), 36);
const ONE_36 = parseFixed('1', 36);
const _oGliqFixed = parseFixed(
parsedReserves._oGLiq.toString(),
36
);
const maxLimitFixed = alphaFixed
.add(ONE_36)
.mul(_oGliqFixed)
.div(ONE_36) // I left this step explicit, but this is better done using a mulDownFixed helper function
.div(2);
Of course you'd already have all variables as BigNumber and those conversions wouldn't be necessary, but I added so it's easier to follow along what each of them represents.
You can also look at how other pools are handling that within the SOR.
Gyro pool for example uses 38 decimals fixed point math, which can be found on gyroSignedFixedPoint.ts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hi @brunoguerios I just pushed several commits that start to address this change.
still work in progress but wanted to get your feedback to make sure we're going in the right direction. See calculateMicroFee
which I moved to BigNumber
. Let me know what you think
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ps calculateMicroFee
is in src/pools/xaveFxPool/fxPoolMath.ts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @andreiashu 👋
Thanks for sharing your progress so I can provide feedback early 😊
Yeah, based on calculateMicroFee
, you're definitely going in the right direction 👍
Thanks for taking the time and applying these changes!
They will help a lot to include FX pools on the new version of the SDK 😃
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hi @brunoguerios we got rid of OldBigNumber
pretty much across our codebase. The functions that are called by the SOR (_exactTokenInForTokenOut
, _tokenInForExactTokenOut
, _spotPriceAfterSwapExactTokenInForTokenOut
and the _derivativeSpotPriceAfter[...]
) are still converting back to OldBigNumber
as expected.
Let me know what you think
…ut us as last of the pools in terms of normalized liquidity; fixed tests;
…ding down to 15 decimals (I must have forgotten that code there);
…potPriceAfterSwapExactTokenInForTokenOut used BigNumber now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a few comments aiming for reducing complexity whenever possible, but none of them are critical, as they don't really change the end result.
The PR looks good to me 👍
I'll sync with John over here on the process of approving/merging/releasing on the next few days and I'll keep you updated.
Feel free to reach out in case you have any questions!
.div(ONE_36) | ||
.mul(safeParseFixed('1', fxOracleDecimals)) | ||
.mul(ONE_36) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should be able to remove this div(ONE_36)
and the mul(ONE_36)
as they are cancelling themselves out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return this._inHigherPrecision( | ||
_exactTokenInForTokenOut, | ||
amount, | ||
poolPairData | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that you're using fixed point math with 36 decimals on fxPoolMath, you should be able to remove this inHigherPrecision
wrapper, right?
I'm just thinking of ways to reduce complexity whenever possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems this one might have to wait until we have SOR converted to fixed-point math as well.
For example, in _derivativeSpotPriceAfterSwapTokenInForExactTokenOut
, because we still have to use OldBigNumber
in _spotPriceAfterSwapTokenInForExactTokenOut
, that means that for both spotPriceBeforeSwap
and _spotPriceAfterSwapTokenInForExactTokenOut
we're doing .div(OLD_ONE_36).decimalPlaces(....)
. I believe this will be easier to fix once we have fixed-point math across SOR. Thoughts?
src/pools/xaveFxPool/fxPoolMath.ts
Outdated
tokenInNumeraire = viewNumeraireAmount( | ||
safeParseFixed(poolPairData.balanceOut.toString(), 36), | ||
poolPairData.decimalsOut, | ||
poolPairData.tokenOutLatestFXPrice, | ||
poolPairData.tokenOutfxOracleDecimals | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I already shared this on TG chat, but I believe it's worth highlighting again, as it seems pretty odd to me:
- Is it intentional that
tokenInNumeraire
is associated withbalanceOut
anddecimalsOut
on this scenario?
Based on the if/else, this results in USDC always being associated with tokenInNumeraire
, disregard of it being tokenIn or tokenOut.
I know this has been like this for a while and that tests are passing, but I believe it's better to double check 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's intentional. But I want to confirm with Ernest. Thanks for raising this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @brunoguerios , thanks for the feedback. We already modified this based on the current way of things in our FxPool logic. It is already included in this PR.
This used to be another functionality of that helper function prior to optimization. Let us know if this looks good on your end.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure thing! Thanks for taking the time to take a look at it 🙏
…orTokenOut`; universalNormalizedLiquidity should return higher values for more advantageous pools;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looks good!
Thanks for taking the time to update to fixed-point math.
I believe there are a few minor improvements that could be done regarding scaling up/down amounts, but I believe we can leave those optimizations to the next version of the SDK/SOR.
OldBigNumber
orbigint.
tsconfig.json
to usees2020
. This was needed because inparseFixedCurveParam
for being able to support bit-shifting forbigint
values_inHigherPrecision
, which allows a function to run under higher-than-18 decimal precision forOldBigNumber