Skip to content
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

Refactor: Change Pool API to have separate methods for JoinPool and JoinPoolNoSwap #2133

Merged
merged 31 commits into from
Sep 7, 2022
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
9f86b96
split out no swap joins on pool interface and implement changes for b…
AlpinYukseloglu Jul 19, 2022
3cb4b3b
minor refactor and comment changes for clarity
AlpinYukseloglu Jul 19, 2022
654fdf4
minor comment changes for review clarity
AlpinYukseloglu Jul 19, 2022
019e3e5
add tests for new calcs
AlpinYukseloglu Jul 19, 2022
1fdf342
Merge branch 'main' into separate-join-pool
AlpinYukseloglu Jul 19, 2022
5633945
fix merge-related issues
AlpinYukseloglu Jul 19, 2022
f1a00eb
add changelog entry
AlpinYukseloglu Jul 19, 2022
08d2b8e
add failure case test and make existing tests more robust
AlpinYukseloglu Jul 20, 2022
eebb7cc
Merge branch 'separate-join-pool' of https://github.com/osmosis-labs/…
AlpinYukseloglu Jul 20, 2022
43772e7
Merge branch 'main' into separate-join-pool
AlpinYukseloglu Jul 20, 2022
79e4232
clean up validation logic
AlpinYukseloglu Jul 20, 2022
82ff209
Merge branch 'separate-join-pool' of https://github.com/osmosis-labs/…
AlpinYukseloglu Jul 20, 2022
a251f7c
Merge branch 'main' into separate-join-pool
czarcas7ic Jul 21, 2022
a370c6e
factor out common denom check and add tests for it
AlpinYukseloglu Aug 8, 2022
dcbb25a
add additional test cases
AlpinYukseloglu Aug 8, 2022
d9fe736
apply new internal fx where relevant and ensure proper testing
AlpinYukseloglu Aug 8, 2022
8806506
Merge branch 'main' into separate-join-pool
AlpinYukseloglu Aug 10, 2022
1a1509c
add test case and improve test readability
AlpinYukseloglu Aug 12, 2022
20f068e
Merge branch 'main' into separate-join-pool
AlpinYukseloglu Aug 13, 2022
4797f8f
add tests for edge cases and clean up existing tests
AlpinYukseloglu Aug 31, 2022
eda585c
add duplicate pool edge case test
AlpinYukseloglu Aug 31, 2022
0e5f5fa
minor comment updates from code review
AlpinYukseloglu Aug 31, 2022
1eae187
remove remainingCoins return value from internal no-swap calcs
AlpinYukseloglu Sep 1, 2022
8b6f485
update mocks
AlpinYukseloglu Sep 5, 2022
6147129
Merge branch 'main' into separate-join-pool
AlpinYukseloglu Sep 5, 2022
0e55e9d
move ensuredenominpool test to amm tests
AlpinYukseloglu Sep 7, 2022
005ae6a
minor comment updates from code review
AlpinYukseloglu Sep 7, 2022
096d5b2
Merge branch 'separate-join-pool' of https://github.com/osmosis-labs/…
AlpinYukseloglu Sep 7, 2022
2f53651
pass ctx through no-swap pool joins
AlpinYukseloglu Sep 7, 2022
d91e0b5
add multi asset and edge case tests to calcnoswap
AlpinYukseloglu Sep 7, 2022
0ef8a99
Merge branch 'main' into separate-join-pool
AlpinYukseloglu Sep 7, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* [#1667](https://github.com/osmosis-labs/osmosis/pull/1673) Move wasm-bindings code out of app package into its own root level package.
* [#2013](https://github.com/osmosis-labs/osmosis/pull/2013) Make `SetParams`, `SetPool`, `SetTotalLiquidity`, and `SetDenomLiquidity` GAMM APIs private
* [#1857](https://github.com/osmosis-labs/osmosis/pull/1857) x/mint rename GetLastHalvenEpochNum to GetLastReductionEpochNum
* [#2133](https://github.com/osmosis-labs/osmosis/pull/2133) Add `JoinPoolNoSwap` and `CalcJoinPoolNoSwapShares` to GAMM pool interface and route `JoinPoolNoSwap` in pool_service.go to new method in pool interface
* [#2394](https://github.com/osmosis-labs/osmosis/pull/2394) Remove unused interface methods from expected keepers of each module
* [#2390](https://github.com/osmosis-labs/osmosis/pull/2390) x/mint remove unused mintCoins parameter from AfterDistributeMintedCoin

Expand Down
2 changes: 1 addition & 1 deletion x/gamm/keeper/pool_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ func (k Keeper) JoinPoolNoSwap(
}
}

sharesOut, err = pool.JoinPool(ctx, neededLpLiquidity, pool.GetSwapFee(ctx))
sharesOut, err = pool.JoinPoolNoSwap(ctx, neededLpLiquidity, pool.GetSwapFee(ctx))
if err != nil {
return nil, sdk.ZeroInt(), err
}
Expand Down
12 changes: 12 additions & 0 deletions x/gamm/pool-models/balancer/amm.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,3 +228,15 @@ func calcPoolSharesInGivenSingleAssetOut(
sharesInFeeIncluded := sharesIn.Quo(sdk.OneDec().Sub(exitFee))
return sharesInFeeIncluded
}

// check to make sure the input denoms exist in the provided pool asset map
AlpinYukseloglu marked this conversation as resolved.
Show resolved Hide resolved
func ensureDenomInPool(poolAssetsByDenom map[string]PoolAsset, tokensIn sdk.Coins) error {
AlpinYukseloglu marked this conversation as resolved.
Show resolved Hide resolved
for _, coin := range tokensIn {
_, ok := poolAssetsByDenom[coin.Denom]
if !ok {
return sdkerrors.Wrapf(types.ErrDenomNotFoundInPool, invalidInputDenomsErrFormat, coin.Denom)
}
}

return nil
}
1 change: 1 addition & 0 deletions x/gamm/pool-models/balancer/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ var (
UpdateIntermediaryPoolAssetsLiquidity = updateIntermediaryPoolAssetsLiquidity

GetPoolAssetsByDenom = getPoolAssetsByDenom
EnsureDenomInPool = ensureDenomInPool
)

func (p *Pool) CalcSingleAssetJoin(tokenIn sdk.Coin, swapFee sdk.Dec, tokenInPoolAsset PoolAsset, totalShares sdk.Int) (numShares sdk.Int, err error) {
Expand Down
76 changes: 66 additions & 10 deletions x/gamm/pool-models/balancer/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,19 @@ func (p *Pool) JoinPool(ctx sdk.Context, tokensIn sdk.Coins, swapFee sdk.Dec) (n
return numShares, nil
}

// JoinPoolNoSwap calculates the number of shares needed for an all-asset join given tokensIn with swapFee applied.
// It updates the liquidity if the pool is joined successfully. If not, returns error.
func (p *Pool) JoinPoolNoSwap(ctx sdk.Context, tokensIn sdk.Coins, swapFee sdk.Dec) (numShares sdk.Int, err error) {
AlpinYukseloglu marked this conversation as resolved.
Show resolved Hide resolved
numShares, newLiquidity, _, err := p.CalcJoinPoolNoSwapShares(ctx, tokensIn, swapFee)
AlpinYukseloglu marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return sdk.Int{}, err
}

// update pool with the calculated share and liquidity needed to join pool
p.IncreaseLiquidity(numShares, newLiquidity)
return numShares, nil
}

// CalcJoinPoolShares calculates the number of shares created to join pool with the provided amount of `tokenIn`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So now this method is basically not called in the codebase anywhere, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CalcJoinPoolShares? Do you mean calls outside of the module? Otherwise it's called in JoinPool

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But JoinPool is no longer called in the state machien right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be missing your point here but I believe JoinPool is still called in JoinSwapExactAmountIn:

sharesOut, err := pool.JoinPool(ctx, tokensIn, pool.GetSwapFee(ctx))

// The input tokens must either be:
// - a single token
Expand All @@ -689,12 +702,10 @@ func (p *Pool) CalcJoinPoolShares(ctx sdk.Context, tokensIn sdk.Coins, swapFee s
return sdk.ZeroInt(), sdk.NewCoins(), err
}

// check to make sure the input denoms exist in the pool
for _, coin := range tokensIn {
_, ok := poolAssetsByDenom[coin.Denom]
if !ok {
return sdk.ZeroInt(), sdk.NewCoins(), sdkerrors.Wrapf(types.ErrDenomAlreadyInPool, invalidInputDenomsErrFormat, coin.Denom)
}
// check to make sure the input denom exists in the pool
err = ensureDenomInPool(poolAssetsByDenom, tokensIn)
if err != nil {
return sdk.ZeroInt(), sdk.NewCoins(), err
p0mvn marked this conversation as resolved.
Show resolved Hide resolved
}

totalShares := p.GetTotalShares()
Expand All @@ -715,12 +726,15 @@ func (p *Pool) CalcJoinPoolShares(ctx sdk.Context, tokensIn sdk.Coins, swapFee s
// * numShares is how many shares are perfectly matched.
// * remainingTokensIn is how many coins we have left to join, that have not already been used.
// if remaining coins is empty, logic is done (we joined all tokensIn)
numShares, remainingTokensIn, err := cfmm_common.MaximalExactRatioJoin(p, sdk.Context{}, tokensIn)
numShares, tokensJoined, remainingTokensIn, err := p.CalcJoinPoolNoSwapShares(ctx, tokensIn, swapFee)
AlpinYukseloglu marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return sdk.ZeroInt(), sdk.NewCoins(), err
}
if remainingTokensIn.Empty() {
tokensJoined = tokensIn

// safely ends the calculation if all input tokens are successfully LP'd
if tokensJoined.IsAnyGT(tokensIn) {
return sdk.ZeroInt(), sdk.NewCoins(), errors.New("an error has occurred, more coins joined than tokens passed in")
AlpinYukseloglu marked this conversation as resolved.
Show resolved Hide resolved
} else if remainingTokensIn.Empty() {
return numShares, tokensJoined, nil
}

Expand All @@ -729,7 +743,6 @@ func (p *Pool) CalcJoinPoolShares(ctx sdk.Context, tokensIn sdk.Coins, swapFee s
// Instead, it mutates the pool assets argument to be further used by the caller.
// * We add the joined coins to our "current pool liquidity" object (poolAssetsByDenom)
// * We increment a variable for our "newTotalShares" to add in the shares that've been added.
tokensJoined = tokensIn.Sub(remainingTokensIn)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Context: CalcJoinPoolNoSwapShares includes this calculation and returns the resulting tokensJoined above

if err := updateIntermediaryPoolAssetsLiquidity(tokensJoined, poolAssetsByDenom); err != nil {
return sdk.ZeroInt(), sdk.NewCoins(), err
}
Expand All @@ -751,6 +764,49 @@ func (p *Pool) CalcJoinPoolShares(ctx sdk.Context, tokensIn sdk.Coins, swapFee s
return numShares, tokensJoined, nil
}

// CalcJoinPoolNoSwapShares calculates the number of shares created to execute an all-asset pool join with the provided amount of `tokensIn`.
// The input tokens must contain exactly the same tokens as the pool contains
AlpinYukseloglu marked this conversation as resolved.
Show resolved Hide resolved
//
// Returns the number of shares created, the amount of coins actually joined into the pool, (in case of not being able to fully join),
// and the remaining tokens in `tokensIn` after joining. If an all-asset join is not possible, returns an error.
//
// Since CalcJoinPoolNoSwapShares is non-mutative, the steps for updating pool shares / liquidity are
// more complex / don't just alter the state.
// We should simplify this logic further in the future using multi-join equations.
func (p *Pool) CalcJoinPoolNoSwapShares(ctx sdk.Context, tokensIn sdk.Coins, swapFee sdk.Dec) (numShares sdk.Int, tokensJoined sdk.Coins, remainingTokens sdk.Coins, err error) {
// get all 'pool assets' (aka current pool liquidity + balancer weight)
poolAssetsByDenom, err := getPoolAssetsByDenom(p.GetAllPoolAssets())
if err != nil {
return sdk.ZeroInt(), sdk.NewCoins(), tokensIn, err
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm just going to point out which branches are not covered by tests.

@AlpinYukseloglu do you mind confirming please if it is possible to introduce test cases to cover these

This is the first branch

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one should actually not be possible as it only fails when there are duplicate assets in a pool and it's not possible to have duplicate denoms in a valid coin set. The error check is just here as a best practice.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it due to using a balancer pool constructor in TestCalcJoinPoolNoSwapShares where the constructor performs this validation?

What if we avoid it using it to trigger an invalid state and achieve full coverage?

We should be able to:

balancerPool := balancer.Pool{
  Address:            types.NewPoolAddress(defaultPoolId).String(),
  Id:                 defaultPoolId,
  PoolParams:         balancer.PoolParams{SwapFee: defaultSwapFee, ExitFee: defaultExitFee},
  PoolAssets:         test.poolAssets,
  FuturePoolGovernor: defaultFutureGovernor,
  TotalShares:        sdk.NewCoin(types.GetPoolShareDenom(defaultPoolId), types.InitPoolSharesSupply),
}

Now, we can force duplicate pool assets

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see the most recent case I added. It is still technically a trivial test case because duplicate pool assets are caught in multiple places throughout this function and ultimately end up in a division by zero even if you comment out all of them, but it should be covered now.

}

err = ensureDenomInPool(poolAssetsByDenom, tokensIn)
if err != nil {
return sdk.ZeroInt(), sdk.NewCoins(), tokensIn, err
}

// ensure that there aren't too many or too few assets in `tokensIn`
if tokensIn.Len() != p.NumAssets() {
return sdk.ZeroInt(), sdk.NewCoins(), tokensIn, errors.New("no-swap joins require LP'ing with all assets in pool")
}

// execute a no-swap join with as many tokens as possible given a perfect ratio:
// * numShares is how many shares are perfectly matched.
// * remainingTokensIn is how many coins we have left to join that have not already been used.
numShares, remainingTokensIn, err := cfmm_common.MaximalExactRatioJoin(p, sdk.Context{}, tokensIn)
AlpinYukseloglu marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return sdk.ZeroInt(), sdk.NewCoins(), tokensIn, err
p0mvn marked this conversation as resolved.
Show resolved Hide resolved
}

// ensure that no more tokens have been joined than is possible with the given `tokensIn`
tokensJoined = tokensIn.Sub(remainingTokensIn)
if tokensJoined.IsAnyGT(tokensIn) {
return sdk.ZeroInt(), sdk.NewCoins(), tokensIn, errors.New("an error has occurred, more coins joined than token In")
p0mvn marked this conversation as resolved.
Show resolved Hide resolved
}

return numShares, tokensJoined, remainingTokensIn, nil
}

// calcJoinSingleAssetTokensIn attempts to calculate single
// asset join for all tokensIn given totalShares in pool,
// poolAssetsByDenom and swapFee. totalShares is the number
Expand Down
141 changes: 141 additions & 0 deletions x/gamm/pool-models/balancer/pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,59 @@ func TestGetPoolAssetsByDenom(t *testing.T) {
}
}

func (suite *KeeperTestSuite) TestEnsureDenomInPool() {
AlpinYukseloglu marked this conversation as resolved.
Show resolved Hide resolved
tests := map[string]struct {
poolAssets []balancer.PoolAsset
tokensIn sdk.Coins
expectPass bool
expectedErr error
}{
"all of tokensIn is in pool asset map": {
poolAssets: []balancer.PoolAsset{defaultOsmoPoolAsset, defaultAtomPoolAsset},
tokensIn: sdk.NewCoins(sdk.NewCoin("uatom", sdk.OneInt())),
expectPass: true,
expectedErr: nil,
},
"one of tokensIn is in pool asset map": {
poolAssets: []balancer.PoolAsset{defaultOsmoPoolAsset, defaultAtomPoolAsset},
tokensIn: sdk.NewCoins(sdk.NewCoin("uatom", sdk.OneInt()), sdk.NewCoin("foo", sdk.OneInt())),
expectPass: false,
expectedErr: types.ErrDenomNotFoundInPool,
},
"none of tokensIn is in pool asset map": {
AlpinYukseloglu marked this conversation as resolved.
Show resolved Hide resolved
poolAssets: []balancer.PoolAsset{defaultOsmoPoolAsset, defaultAtomPoolAsset},
tokensIn: sdk.NewCoins(sdk.NewCoin("foo", sdk.OneInt())),
expectPass: false,
expectedErr: types.ErrDenomNotFoundInPool,
},
AlpinYukseloglu marked this conversation as resolved.
Show resolved Hide resolved
}

for name, tc := range tests {
suite.Run(name, func() {
suite.SetupTest()

k := suite.App.GAMMKeeper

poolId := suite.PrepareBalancerPoolWithPoolAsset(tc.poolAssets)
poolI, err := k.GetPoolAndPoke(suite.Ctx, poolId)
suite.Require().NoError(err, "test: %s", name)
balancerPool, isPool := poolI.(*balancer.Pool)
suite.Require().True(isPool, "test: %s", name)

poolAssetsByDenom, err := balancer.GetPoolAssetsByDenom(balancerPool.GetAllPoolAssets())
suite.Require().NoError(err, "test: %s", name)
p0mvn marked this conversation as resolved.
Show resolved Hide resolved

err = balancer.EnsureDenomInPool(poolAssetsByDenom, tc.tokensIn)

if tc.expectPass {
suite.Require().NoError(err, "test: %s", name)
} else {
suite.Require().ErrorIs(err, tc.expectedErr, "test: %s", name)
}
})
}
}

// TestCalculateAmountOutAndIn_InverseRelationship tests that the same amount of token is guaranteed upon
// sequential operation of CalcInAmtGivenOut and CalcOutAmtGivenIn.
func (suite *BalancerTestSuite) TestBalancerCalculateAmountOutAndIn_InverseRelationship(t *testing.T) {
Expand Down Expand Up @@ -1218,3 +1271,91 @@ func TestIsActive(t *testing.T) {
})
}
}

func TestCalcJoinPoolNoSwapShares(t *testing.T) {
balancerPoolAsset := []balancer.PoolAsset{
{Token: sdk.NewInt64Coin("foo", 100), Weight: sdk.NewIntFromUint64(5)},
{Token: sdk.NewInt64Coin("bar", 100), Weight: sdk.NewIntFromUint64(5)},
}

tests := map[string]struct {
tokensIn sdk.Coins
expNumShare sdk.Int
expTokensJoined sdk.Coins
expPoolAssets sdk.Coins
expRemainingCoins sdk.Coins
expectPass bool
}{
"two asset pool, same tokenIn ratio": {
tokensIn: sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(10)), sdk.NewCoin("bar", sdk.NewInt(10))),
expNumShare: sdk.NewIntFromUint64(10000000000000000000),
expTokensJoined: sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(10)), sdk.NewCoin("bar", sdk.NewInt(10))),
expPoolAssets: sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(100)), sdk.NewCoin("bar", sdk.NewInt(100))),
expRemainingCoins: sdk.Coins{},
expectPass: true,
},
"two asset pool, different tokenIn ratio with pool": {
tokensIn: sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(10)), sdk.NewCoin("bar", sdk.NewInt(11))),
expNumShare: sdk.NewIntFromUint64(10000000000000000000),
expTokensJoined: sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(10)), sdk.NewCoin("bar", sdk.NewInt(10))),
expPoolAssets: sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(100)), sdk.NewCoin("bar", sdk.NewInt(100))),
expRemainingCoins: sdk.NewCoins(sdk.NewCoin("bar", sdk.NewIntFromUint64(1))),
expectPass: true,
},
"two asset pool, no-swap join attempt with one asset": {
tokensIn: sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(10))),
expNumShare: sdk.NewIntFromUint64(0),
expTokensJoined: sdk.Coins{},
expPoolAssets: sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(100)), sdk.NewCoin("bar", sdk.NewInt(100))),
czarcas7ic marked this conversation as resolved.
Show resolved Hide resolved
expRemainingCoins: sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(10))),
expectPass: false,
},
"two asset pool, no-swap join attempt with one valid and one invalid asset": {
tokensIn: sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(10)), sdk.NewCoin("baz", sdk.NewInt(10))),
expNumShare: sdk.NewIntFromUint64(0),
expTokensJoined: sdk.Coins{},
expPoolAssets: sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(100)), sdk.NewCoin("bar", sdk.NewInt(100))),
expRemainingCoins: sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(10)), sdk.NewCoin("baz", sdk.NewInt(10))),
expectPass: false,
},
"two asset pool, no-swap join attempt with two invalid assets": {
tokensIn: sdk.NewCoins(sdk.NewCoin("baz", sdk.NewInt(10)), sdk.NewCoin("qux", sdk.NewInt(10))),
expNumShare: sdk.NewIntFromUint64(0),
expTokensJoined: sdk.Coins{},
expPoolAssets: sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(100)), sdk.NewCoin("bar", sdk.NewInt(100))),
expRemainingCoins: sdk.NewCoins(sdk.NewCoin("baz", sdk.NewInt(10)), sdk.NewCoin("qux", sdk.NewInt(10))),
expectPass: false,
},
}

for name, test := range tests {
t.Run(name, func(t *testing.T) {
ctx := sdk.Context{}
balancerPool, err := balancer.NewBalancerPool(
defaultPoolId,
balancer.PoolParams{SwapFee: defaultSwapFee, ExitFee: defaultExitFee},
balancerPoolAsset,
defaultFutureGovernor,
defaultCurBlockTime,
)
require.NoError(t, err)

numShare, tokensJoined, remainingCoins, err := balancerPool.CalcJoinPoolNoSwapShares(ctx, test.tokensIn, balancerPool.GetSwapFee(ctx))
poolAssets := sdk.NewCoins(balancerPool.PoolAssets[0].Token, balancerPool.PoolAssets[1].Token)

if test.expectPass {
require.NoError(t, err)
require.Equal(t, test.expPoolAssets, poolAssets)
require.Equal(t, test.expNumShare, numShare)
require.Equal(t, test.expTokensJoined, tokensJoined)
require.Equal(t, test.expRemainingCoins, remainingCoins)
} else {
require.Error(t, err)
require.Equal(t, test.expPoolAssets, poolAssets)
require.Equal(t, test.expNumShare, numShare)
require.Equal(t, test.expTokensJoined, tokensJoined)
require.Equal(t, test.expRemainingCoins, remainingCoins)
}
})
AlpinYukseloglu marked this conversation as resolved.
Show resolved Hide resolved
}
}
10 changes: 10 additions & 0 deletions x/gamm/pool-models/stableswap/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,11 +258,21 @@ func (p *Pool) CalcJoinPoolShares(ctx sdk.Context, tokensIn sdk.Coins, swapFee s
return pCopy.joinPoolSharesInternal(ctx, tokensIn, swapFee)
}

// TODO: implement this
AlpinYukseloglu marked this conversation as resolved.
Show resolved Hide resolved
func (p *Pool) CalcJoinPoolNoSwapShares(ctx sdk.Context, tokensIn sdk.Coins, swapFee sdk.Dec) (numShares sdk.Int, newLiquidity sdk.Coins, remainingCoins sdk.Coins, err error) {
return sdk.ZeroInt(), nil, nil, err
}

func (p *Pool) JoinPool(ctx sdk.Context, tokensIn sdk.Coins, swapFee sdk.Dec) (numShares sdk.Int, err error) {
numShares, _, err = p.joinPoolSharesInternal(ctx, tokensIn, swapFee)
return numShares, err
}

// TODO: implement this
AlpinYukseloglu marked this conversation as resolved.
Show resolved Hide resolved
func (p *Pool) JoinPoolNoSwap(ctx sdk.Context, tokensIn sdk.Coins, swapFee sdk.Dec) (numShares sdk.Int, err error) {
return sdk.ZeroInt(), err
}

func (p *Pool) ExitPool(ctx sdk.Context, exitingShares sdk.Int, exitFee sdk.Dec) (exitingCoins sdk.Coins, err error) {
exitingCoins, err = p.CalcExitPoolCoinsFromShares(ctx, exitingShares, exitFee)
if err != nil {
Expand Down
9 changes: 9 additions & 0 deletions x/gamm/types/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,19 @@ type PoolI interface {
// Pools are expected to guarantee LP'ing at the exact ratio, and single sided LP'ing.
JoinPool(ctx sdk.Context, tokensIn sdk.Coins, swapFee sdk.Dec) (numShares sdk.Int, err error)

// JoinPoolNoSwap joins the pool with an all-asset join using the maximum amount possible given the tokensIn provided.
// This function is mutative and updates the pool's internal state if there is no error.
// Pools are expected to guarantee LP'ing at the exact ratio.
JoinPoolNoSwap(ctx sdk.Context, tokensIn sdk.Coins, swapFee sdk.Dec) (numShares sdk.Int, err error)

// CalcJoinPoolShares returns how many LP shares JoinPool would return on these arguments.
// This does not mutate the pool, or state.
CalcJoinPoolShares(ctx sdk.Context, tokensIn sdk.Coins, swapFee sdk.Dec) (numShares sdk.Int, newLiquidity sdk.Coins, err error)

// CalcJoinPoolNoSwapShares returns how many LP shares JoinPoolNoSwap would return on these arguments.
// This does not mutate the pool, or state.
CalcJoinPoolNoSwapShares(ctx sdk.Context, tokensIn sdk.Coins, swapFee sdk.Dec) (numShares sdk.Int, newLiquidity sdk.Coins, remainingTokens sdk.Coins, err error)

// ExitPool exits #numShares LP shares from the pool, decreases its internal liquidity & LP share totals,
// and returns the number of coins that are being returned.
// This mutates the pool and state.
Expand Down