-
Notifications
You must be signed in to change notification settings - Fork 589
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
Extract functions and methods from CalcJoinPoolShares; unit tests #1721
Conversation
x/gamm/pool-models/balancer/amm.go
Outdated
numShares.Add(newNumSharesFromRemaining) | ||
newLiquidity = newLiquidity.Add(newLiquidityFromRemaining...) |
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.
Unit tests for CalcJoinPoolShares
validating that these updates happen should be added in a separate PR
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.
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.
Thank you for the PR @p0mvn. Left few notes, really curious whether the calculation for multi-asset is accurate as i was trying to figure that out for hours today 😅
Thank you for all the human readable equation + wolfram too. Really helpful!
}, | ||
}, | ||
tokensIn: sdk.NewCoins(sdk.NewInt64Coin("uosmo", 50_000), sdk.NewInt64Coin("uatom", 50_000)), | ||
expectShares: sdk.NewInt(2_499_999_968_750 * 2), |
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.
Are you sure you can add both shares to calculate total shares for two asset deposit ?
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.
As per my comment above, https://github.com/osmosis-labs/osmosis/pull/1721/files#r893463274
here, we can add shares because these are essentially done by single asset joining each token.
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.
Seems reasonable to me.
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'm confused as to why expectShares
is double what is in the previous test when the total liquidity isn't being doubled. From the balancer whitepaper:
An “all-asset” deposit has to follow the distribution of existing assets in the pool. If the deposit contains 10%
of each of the assets already in the pool, then the Value Function will increase by 10% and the depositor will
be minted 10% of the current outstanding pool token supply.
Also as per my comment above, it's not clear to me why we're implementing/testing a case where we single asset join two assets into a 2-asset pool when MaximalExactRatioJoin
would do the trick with no swap fees (and would be the intended/expected behavior when a pool is joined) – am I missing something @p0mvn?
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'm confused as to why expectShares is double what is in the previous test when the total liquidity isn't being doubled
The logic was the following - here we are adding 2 tokens in that have equal weights and amounts in, so the liquidity would double. In the previous case, there was only one token in.
However, it seems that these should still not be equal because after the first join we would have more shares created for one of the tokens, right? As a result, the second join would have fewer shares returned than the first one. Seems that this test is passing because of the error tolerance
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.
Also as per my comment above, it's not clear to me why we're implementing/testing a case where we single asset join two assets into a 2-asset pool when MaximalExactRatioJoin would do the trick with no swap fees (and would be the intended/expected behavior when a pool is joined) – am I missing something
The goal was to make the function be independent of what the caller might do. I think the suggested check is useful but should belong to the caller of this function. 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.
I'm confused as to why expectShares is double what is in the previous test when the total liquidity isn't being doubled
The logic was the following - here we are adding 2 tokens in that have equal weights and amounts in, so the liquidity would double. In the previous case, there was only one token in.
However, it seems that these should still not be equal because after the first join we would have more shares created for one of the tokens, right? As a result, the second join would have fewer shares returned than the first one. Seems that this test is passing because of the error tolerance
This is interesting – I wonder if we can set up a case where this falls outside of error tolerance just for proper coverage? Or would it always pass due to error tolerance?
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.
Also as per my comment above, it's not clear to me why we're implementing/testing a case where we single asset join two assets into a 2-asset pool when MaximalExactRatioJoin would do the trick with no swap fees (and would be the intended/expected behavior when a pool is joined) – am I missing something
The goal was to make the function be independent of what the caller might do. I think the suggested check is useful but should belong to the caller of this function. Let me know what you think
I hear you on this, agreed!
// calcJoinSingleAssetTokensIn attempts to calculate single | ||
// asset join for all tokensIn given totalShares in pool, | ||
// poolAssetsByDenom and swapFee. totalShares is the number | ||
// of shares in pool before beginnning to join any of the tokensIn. | ||
// | ||
// Returns totalNewShares and totalNewLiquidity from joining all tokensIn | ||
// by mimicking individually single asset joining each. | ||
// or error if fails to calculate join for any of the tokensIn. | ||
func (p *Pool) calcJoinSingleAssetTokensIn(tokensIn sdk.Coins, totalShares sdk.Int, poolAssetsByDenom map[string]PoolAsset, swapFee sdk.Dec) (sdk.Int, sdk.Coins, error) { |
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.
Am I correct in saying that this function assumes len(tokensIn)
< len(poolAssets)
i.e. that the number of tokens in tokensIn
is less than the total number of assets/denoms in the pool since otherwise, we would run MaximalExactRatioJoin
instead of running calcSingleAssetJoin
on each asset?
If so, it might be worth enforcing this with a check at the beginning of the function so that we only have one valid way of doing a multi-asset join: MaximalExactRatioJoin
following by calcJoinSingleAssetTokensIn
on the remaining assets
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.
While I agree that this check is useful, I think that we should have it in the caller of this function, not inside this function itself.
A function should work independently of its caller. Otherwise, we would add an invariant that might restrict its use in other cases.
I will investigate this further
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.
What do you think about having this check here:
f6071c9
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.
A function should work independently of its caller. Otherwise, we would add an invariant that might restrict its use in other cases.
Generally agree with this - probably a good idea to leave it as it is to not break abstraction
What do you think about having this check here: f6071c9
This addresses a separate but important point & lets us have an error case we can use for testing. Great addition
}, | ||
}, | ||
tokensIn: sdk.NewCoins(sdk.NewInt64Coin("uosmo", 50_000), sdk.NewInt64Coin("uatom", 50_000)), | ||
expectShares: sdk.NewInt(2_499_999_968_750 * 2), |
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'm confused as to why expectShares
is double what is in the previous test when the total liquidity isn't being doubled. From the balancer whitepaper:
An “all-asset” deposit has to follow the distribution of existing assets in the pool. If the deposit contains 10%
of each of the assets already in the pool, then the Value Function will increase by 10% and the depositor will
be minted 10% of the current outstanding pool token supply.
Also as per my comment above, it's not clear to me why we're implementing/testing a case where we single asset join two assets into a 2-asset pool when MaximalExactRatioJoin
would do the trick with no swap fees (and would be the intended/expected behavior when a pool is joined) – am I missing something @p0mvn?
}, | ||
}, | ||
tokensIn: sdk.NewCoins(sdk.NewInt64Coin("uosmo", 50_000), sdk.NewInt64Coin("uatom", 50_000)), | ||
expectShares: sdk.NewInt(2_487_500_000_000 * 2), |
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.
Same question as my comment above
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.
Will resolve this once figure out an appropriate path forward
x/gamm/pool-models/balancer/amm.go
Outdated
// update liquidity for accurate calcSingleAssetJoin calculation | ||
newLiquidity = tokensIn.Sub(remCoins) | ||
for _, coin := range newLiquidity { | ||
poolAsset := poolAssetsByDenom[coin.Denom] | ||
poolAsset.Token.Amount = poolAssetsByDenom[coin.Denom].Token.Amount.Add(coin.Amount) | ||
poolAssetsByDenom[coin.Denom] = poolAsset | ||
} |
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.
Comment for posterity, these lines were moved to line 306
* Improve comments / abstractions * Add eror * Add swap fee note * Update x/gamm/pool-models/balancer/amm.go Co-authored-by: Aleksandr Bezobchuk <[email protected]> * More comments Co-authored-by: Aleksandr Bezobchuk <[email protected]>
LGTM to merge after the last few commits |
) * Fix insufficient total share creation * More correctx * small refactor to expose methods for unit tests * fix problem with newLiquidity, better names and more comments * fix typo * add TestCalcSingleAssetJoin * add test case to TestCalcSingleAssetJoin * add test case to TestCalcSingleAssetJoin * add another Wolfram test case to TestCalcSingleAssetJoin * another test case for TestCalcSingleAssetJoin * remove errors from TestCalcSingleAssetJoin * add TestCalcJoinMultipleSingleAssetTokensIn * add complex case for TestCalcJoinMultipleSingleAssetTokensIn * add assetions for liquidity * add no tokens in TestCalcJoinMultipleSingleAssetTokensIn * update newLiquidity * remove else clause * currTotalShares * rename to CalcJoinSingleAssetTokensIn * refactor shares logic in calcJoinSingleAssetTokensIn * fix comment in test * update numShares * use context from parameter * Update x/gamm/pool-models/balancer/amm_test.go Co-authored-by: Matt, Park <[email protected]> * Update x/gamm/pool-models/balancer/amm_test.go Co-authored-by: Matt, Park <[email protected]> * rename remainingTokensIn * remove TestCalcSingleAssetJoin * copy godoc for CalcJoinPoolShares from pool interface * Update x/gamm/pool-models/balancer/amm.go Co-authored-by: Aleksandr Bezobchuk <[email protected]> * move getPoolAssetsByDenom function and test to another PR * simplify to use recently merged GetPoolAssetsByDenom function * remove redundant time * typo * update name to updatePoolAssetsLiquidity * add validation for giving tokenIn that is not in pool to calcSingleAssetJoin * specify that balancer equation is modified with swapFeeRatio added * Fix merge conflict I introduced * Improve comments / abstractions (#1761) * Improve comments / abstractions * Add eror * Add swap fee note * Update x/gamm/pool-models/balancer/amm.go Co-authored-by: Aleksandr Bezobchuk <[email protected]> * More comments Co-authored-by: Aleksandr Bezobchuk <[email protected]> * mild test cleanup Co-authored-by: Dev Ojha <[email protected]> Co-authored-by: Matt, Park <[email protected]> Co-authored-by: Aleksandr Bezobchuk <[email protected]> Co-authored-by: Dev Ojha <[email protected]> (cherry picked from commit 9432b92)
) (#1766) * Fix insufficient total share creation * More correctx * small refactor to expose methods for unit tests * fix problem with newLiquidity, better names and more comments * fix typo * add TestCalcSingleAssetJoin * add test case to TestCalcSingleAssetJoin * add test case to TestCalcSingleAssetJoin * add another Wolfram test case to TestCalcSingleAssetJoin * another test case for TestCalcSingleAssetJoin * remove errors from TestCalcSingleAssetJoin * add TestCalcJoinMultipleSingleAssetTokensIn * add complex case for TestCalcJoinMultipleSingleAssetTokensIn * add assetions for liquidity * add no tokens in TestCalcJoinMultipleSingleAssetTokensIn * update newLiquidity * remove else clause * currTotalShares * rename to CalcJoinSingleAssetTokensIn * refactor shares logic in calcJoinSingleAssetTokensIn * fix comment in test * update numShares * use context from parameter * Update x/gamm/pool-models/balancer/amm_test.go Co-authored-by: Matt, Park <[email protected]> * Update x/gamm/pool-models/balancer/amm_test.go Co-authored-by: Matt, Park <[email protected]> * rename remainingTokensIn * remove TestCalcSingleAssetJoin * copy godoc for CalcJoinPoolShares from pool interface * Update x/gamm/pool-models/balancer/amm.go Co-authored-by: Aleksandr Bezobchuk <[email protected]> * move getPoolAssetsByDenom function and test to another PR * simplify to use recently merged GetPoolAssetsByDenom function * remove redundant time * typo * update name to updatePoolAssetsLiquidity * add validation for giving tokenIn that is not in pool to calcSingleAssetJoin * specify that balancer equation is modified with swapFeeRatio added * Fix merge conflict I introduced * Improve comments / abstractions (#1761) * Improve comments / abstractions * Add eror * Add swap fee note * Update x/gamm/pool-models/balancer/amm.go Co-authored-by: Aleksandr Bezobchuk <[email protected]> * More comments Co-authored-by: Aleksandr Bezobchuk <[email protected]> * mild test cleanup Co-authored-by: Dev Ojha <[email protected]> Co-authored-by: Matt, Park <[email protected]> Co-authored-by: Aleksandr Bezobchuk <[email protected]> Co-authored-by: Dev Ojha <[email protected]> (cherry picked from commit 9432b92) Co-authored-by: Roman <[email protected]>
Closes: #XXX
What is the purpose of the change
Extract functions and methods in
CalcJoinPoolShares
to be able to unit test each one separately. Add more comments explaining steps in detail. Add unit tests for the newly extracted functions.Functions that were created:
getPoolAssetsByDenom
updateIntermediaryPoolAssets
calcJoinMultipleSingleAssetTokensIn
Additionally, added
calcSingleAssetJoin
test cases with various inputs. For each test case, verified the expected value with Wolfram. Most values are mismatched by an insignificant number that is checked with multiplicativeErrTolerance
of"0.0000001"
ErrTolerance
related to when the additive difference is nil so made a quick fixTesting and Verifying
This change added tests and can be verified as follows:
go test -timeout 30s -run ^TestGetPoolAssetsByDenom$ github.com/osmosis-labs/osmosis/v7/x/gamm/pool-models/balancer
go test -timeout 30s -run ^TestUpdateIntermediaryPoolAssets$ github.com/osmosis-labs/osmosis/v7/x/gamm/pool-models/balancer
go test -timeout 30s -run ^TestCalcSingleAssetJoin$ github.com/osmosis-labs/osmosis/v7/x/gamm/pool-models/balancer
go test -timeout 30s -run ^TestCalcSingleAssetJoin$ github.com/osmosis-labs/osmosis/v7/x/gamm/pool-models/balancer
go test -timeout 30s -run ^TestCalcJoinSingleAssetTokensIn$ github.com/osmosis-labs/osmosis/v7/x/gamm/pool-models/balancer
Documentation and Release Note
Unreleased
section inCHANGELOG.md
? no