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(CL): change full range definition #6380

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### State Breaking

* [#6344](https://github.com/osmosis-labs/osmosis/pull/6344) fix: set name, display and symbol of denom metadata in tokenfactory's CreateDenom
### Misc Improvements

* [#6380](https://github.com/osmosis-labs/osmosis/pull/6380) Change full range definition to 10^-30 to 10^38.

### Bug Fixes

Expand Down
57 changes: 46 additions & 11 deletions x/concentrated-liquidity/fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,12 @@ func TestFuzz_Many(t *testing.T) {
func (s *KeeperTestSuite) TestFuzz_GivenSeed() {
// Seed 1688572291 - gives mismatch between tokenIn given to "out given in" and token in returned from "in given out"
// Seed 1688658883- causes an error in swap in given out due to rounding (acceptable).
r := rand.New(rand.NewSource(1688658883))
// Seed 1694529692 - proves issues in rounding direction of GetNextSqrtPriceFromAmount0InRoundingUp, proving
// that we must not QuoRoundUp for the last term in the formula.
// To repro: set up a breakpoint at the top of computeSwapOutGivenIn, and set count to 15.
// On the third (last) swap step for that swap, observe that the final `sqrtPriceNext` is off by one
// BigDec ULP, showing that this rounding bheavior was the issue.
r := rand.New(rand.NewSource(1694694614))
s.individualFuzz(r, 0, 30, 10)

s.validateNoErrors(s.collectedErrors)
Expand Down Expand Up @@ -186,6 +191,7 @@ func (s *KeeperTestSuite) swapRandomAmount(r *rand.Rand, pool types.Concentrated
fmt.Println("swap type: random amount")
swapInDenom, swapOutDenom := zfoToDenoms(zfo, pool)
swapAmt := randomIntAmount(r)

swapInCoin := sdk.NewCoin(swapInDenom, swapAmt)
return s.swap(pool, swapInCoin, swapOutDenom)
}
Expand Down Expand Up @@ -222,16 +228,6 @@ func (s *KeeperTestSuite) swapNearInitializedTickBoundary(r *rand.Rand, pool typ
}

func (s *KeeperTestSuite) swapNearTickBoundary(r *rand.Rand, pool types.ConcentratedPoolExtension, targetTick int64, zfo bool) (didSwap bool, fatalErr bool) {
// TODO: remove this limit upon completion of the refactor in:
// https://github.com/osmosis-labs/osmosis/issues/5726
// Due to an intermediary refactor step where we have
// full range positions created in the extended full range it
// sometimes tries to swap to the V2 MinInitializedTick that
// is not supported yet by the rest of the system.
if targetTick < types.MinInitializedTick {
return false, false
}

swapInDenom, swapOutDenom := zfoToDenoms(zfo, pool)
// TODO: Confirm accuracy of this method.
amountInRequired, curLiquidity, _ := s.computeSwapAmounts(pool.GetId(), pool.GetCurrentSqrtPrice(), targetTick, zfo, false)
Expand Down Expand Up @@ -281,6 +277,14 @@ func tickAmtChange(r *rand.Rand, targetAmount osmomath.Dec) osmomath.Dec {
}

func (s *KeeperTestSuite) swap(pool types.ConcentratedPoolExtension, swapInFunded sdk.Coin, swapOutDenom string) (didSwap bool, fatalErr bool) {
atLeastOneOut, shouldSkip := shouldSkipDueToInvalidAmountInChoice(swapInFunded.Amount, swapInFunded.Denom, pool)

if shouldSkip {
return false, false
}

swapInFunded.Amount = atLeastOneOut

// Reason for adding one int:
// Seed 1688658883- causes an error in swap in given out due to rounding (acceptable). This is because we use
// token out from "swap out given in" as an input to "in given out". "in given out" rounds by one in pool's favor
Expand Down Expand Up @@ -582,3 +586,34 @@ func roundTickDownSpacing(tickIndex int64, tickSpacing int64) int64 {
func randomIntAmount(r *rand.Rand) osmomath.Int {
return osmomath.NewInt(r.Int63n(maxAmountDeposited))
}

// returns true if the swap should be skipped due to either producing 0 out at this spot price,
// or failing to get the spot price to confirm.
//
// Reasonn for this: at low min spot prices, such cases might lead to an infinite loop error.
// We don't want to skip such error as acceptable, as a result, we
// prevent amounts of swap in that yield zero out in general.
func shouldSkipDueToInvalidAmountInChoice(amountIn osmomath.Int, denomIn string, pool types.ConcentratedPoolExtension) (osmomath.Int, bool) {
spotPrice := pool.GetCurrentSqrtPrice().PowerInteger(2)

amountOutPriceInTermsOfIn := spotPrice
if denomIn == pool.GetToken1() {
amountOutPriceInTermsOfIn = osmomath.OneBigDec().Quo(spotPrice)

// Failed to get an approriate amount to swap in but not fatal.
if amountOutPriceInTermsOfIn.IsZero() {
return osmomath.Int{}, true
}
}
amountOut := amountOutPriceInTermsOfIn.Mul(osmomath.NewBigDecFromBigInt(amountIn.BigInt()))
if amountOut.IsZero() {
return osmomath.Int{}, true
}

amountInPriceInTermsOfOut := osmomath.OneBigDec().Quo(amountOutPriceInTermsOfIn).Ceil()

// Add amount in for randomness
atLeastOneOut := amountInPriceInTermsOfOut.DecRoundUp().TruncateInt().Add(amountIn)

return atLeastOneOut, false
}
2 changes: 1 addition & 1 deletion x/concentrated-liquidity/incentives_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3556,7 +3556,7 @@ func (s *KeeperTestSuite) TestGetIncentiveRecordSerialized() {
func (s *KeeperTestSuite) TestCollectIncentives_MinSpotPriceMigration() {
s.SetupTest()

incentiveAmount := osmomath.NewInt(1000)
incentiveAmount := osmomath.NewInt(1_000_000_000)
incentiveCoin := sdk.NewCoin(OSMO, incentiveAmount)
expectedTotalIncentiveRewards := sdk.NewCoins(incentiveCoin)
_, positions, _ := s.swapToMinTickAndBack(osmomath.ZeroDec(), expectedTotalIncentiveRewards)
Expand Down
18 changes: 11 additions & 7 deletions x/concentrated-liquidity/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,8 @@ const (
)

var (
// TODO: switch:
// DefaultMinTick to tyoes.MinInitializedTickV2 and
// DefaultMinCurrentTick to types.MinCurrentTickV2 upon
// completion of https://github.com/osmosis-labs/osmosis/issues/5726
DefaultMinTick, DefaultMaxTick = types.MinInitializedTick, types.MaxTick
DefaultMinCurrentTick = types.MinCurrentTick
DefaultMinTick, DefaultMaxTick = types.MinInitializedTickV2, types.MaxTick
DefaultMinCurrentTick = types.MinCurrentTickV2
DefaultLowerPrice = osmomath.NewDec(4545)
DefaultLowerTick = int64(30545000)
DefaultUpperPrice = osmomath.NewDec(5500)
Expand Down Expand Up @@ -523,6 +519,9 @@ func (s *KeeperTestSuite) swapToMinTickAndBack(spreadFactor osmomath.Dec, incent
incentiveCreator := s.TestAccs[2]
s.FundAcc(incentiveCreator, incentiveRewards)

// By default we want to swap all the way to MinInitializedTickV2
shouldCrossTick := true

// Create incentive rewards if desired
if !incentiveRewards.Empty() {
s.Require().Len(incentiveRewards, 1)
Expand All @@ -532,10 +531,15 @@ func (s *KeeperTestSuite) swapToMinTickAndBack(spreadFactor osmomath.Dec, incent
s.Ctx, poolId, s.TestAccs[2],
incentiveCoin, incentiveCoin.Amount.ToLegacyDec().Quo(osmomath.NewDec(migrationTestTimeBetweenSwapsSecs)), s.Ctx.BlockTime(), time.Nanosecond)
s.Require().NoError(err)

// With incentive tests, we do not want to cross the MinInitializedTick.
// If that happens, the liquidity in the current tick is zero. As a result,
// the incentive distirbution fails.
shouldCrossTick = false
}

// esimate amount in to swap left all the way until the new min initialized tick
amountZeroIn, _, _ := s.computeSwapAmounts(poolId, pool.GetCurrentSqrtPrice(), types.MinInitializedTickV2, true, false)
amountZeroIn, _, _ := s.computeSwapAmounts(poolId, pool.GetCurrentSqrtPrice(), types.MinInitializedTickV2, true, !shouldCrossTick)

// Fund swapper
swapper := s.TestAccs[1]
Expand Down
8 changes: 4 additions & 4 deletions x/concentrated-liquidity/lp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -598,8 +598,8 @@ func (s *KeeperTestSuite) TestWithdrawPosition() {
// * liquidity = FullRangeLiquidityAmt
// * sqrtPriceB = DefaultCurrSqrtPrice
// * sqrtPriceA = MinSqrtPrice
// Exact calculation: https://www.wolframalpha.com/input?i=70710678.118654752940000000+*+%2870.710678118654752440+-+0.000001000000000000%29
amount1Expected: osmomath.NewInt(4999999929),
// Exact calculation: https://www.wolframalpha.com/input?i=70710678.118654752940000000+*+%2870.710678118654752440+-+0.000000000000001%29
amount1Expected: osmomath.NewInt(4999999999),
liquidityAmount: FullRangeLiquidityAmt,
underlyingLockId: 1,
},
Expand Down Expand Up @@ -1028,8 +1028,8 @@ func (s *KeeperTestSuite) TestAddToPosition() {
// We calculate calc amount1 by using the following equation:
// liq * (sqrtPriceB - sqrtPriceA), where liq is equal to the original joined liq + added liq, sqrtPriceB is current sqrt price, and sqrtPriceA is min sqrt price.
// Note that these numbers were calculated using `GetLiquidityFromAmounts` and `TickToSqrtPrice` and thus assume correctness of those functions.
// https://www.wolframalpha.com/input?i=212041526.154556192317664016+*+%2870.728769315114743566+-+0.000001000000000000%29
amount1Expected: osmomath.NewInt(14997435977),
// https://www.wolframalpha.com/input?i=212041526.154556192317664016+*+%2870.728769315114743566+-+0.000000000000001000%29
amount1Expected: osmomath.NewInt(14997436189),
},
timeElapsed: defaultTimeElapsed,
amount0ToAdd: amount0PerfectRatio,
Expand Down
4 changes: 2 additions & 2 deletions x/concentrated-liquidity/model/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,10 +298,10 @@ func (p *Pool) ApplySwap(newLiquidity osmomath.Dec, newCurrentTick int64, newCur
}

// Check if the new tick provided is within boundaries of the pool's precision factor.
if newCurrentTick < types.MinCurrentTick || newCurrentTick > types.MaxTick {
if newCurrentTick < types.MinCurrentTickV2 || newCurrentTick > types.MaxTick {
return types.TickIndexNotWithinBoundariesError{
MaxTick: types.MaxTick,
MinTick: types.MinCurrentTick,
MinTick: types.MinCurrentTickV2,
ActualTick: newCurrentTick,
}
}
Expand Down
8 changes: 4 additions & 4 deletions x/concentrated-liquidity/model/pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ func (s *ConcentratedPoolTestSuite) TestApplySwap() {
currentTick: DefaultCurrTick,
currentSqrtPrice: DefaultCurrSqrtPrice,
newLiquidity: DefaultLiquidityAmt,
newTick: types.MinInitializedTick,
newTick: types.MinInitializedTickV2,
newSqrtPrice: DefaultCurrSqrtPrice,
expectErr: nil,
},
Expand All @@ -396,7 +396,7 @@ func (s *ConcentratedPoolTestSuite) TestApplySwap() {
currentTick: DefaultCurrTick,
currentSqrtPrice: DefaultCurrSqrtPrice,
newLiquidity: DefaultLiquidityAmt,
newTick: types.MinCurrentTick,
newTick: types.MinCurrentTickV2,
newSqrtPrice: DefaultCurrSqrtPrice,
expectErr: nil,
},
Expand All @@ -410,7 +410,7 @@ func (s *ConcentratedPoolTestSuite) TestApplySwap() {
newSqrtPrice: DefaultCurrSqrtPrice,
expectErr: types.TickIndexNotWithinBoundariesError{
MaxTick: types.MaxTick,
MinTick: types.MinCurrentTick,
MinTick: types.MinCurrentTickV2,
ActualTick: math.MaxInt64,
},
},
Expand All @@ -424,7 +424,7 @@ func (s *ConcentratedPoolTestSuite) TestApplySwap() {
newSqrtPrice: DefaultCurrSqrtPrice,
expectErr: types.TickIndexNotWithinBoundariesError{
MaxTick: types.MaxTick,
MinTick: types.MinCurrentTick,
MinTick: types.MinCurrentTickV2,
ActualTick: math.MinInt64,
},
},
Expand Down
2 changes: 1 addition & 1 deletion x/concentrated-liquidity/pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,7 @@ func (s *KeeperTestSuite) TestGetUserUnbondingPositions() {
PositionId: 3,
Address: defaultAddress.String(),
PoolId: 1,
LowerTick: types.MinInitializedTick,
LowerTick: types.MinInitializedTickV2,
UpperTick: types.MaxTick,
JoinTime: defaultBlockTime,
Liquidity: osmomath.MustNewDecFromStr("10000.000000000000001000"),
Expand Down
6 changes: 3 additions & 3 deletions x/concentrated-liquidity/position.go
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ func (k Keeper) SetPosition(ctx sdk.Context,
}

// If position is full range, update the pool ID to total full range liquidity mapping.
if lowerTick == types.MinInitializedTick && upperTick == types.MaxTick {
if lowerTick == types.MinInitializedTickV2 && upperTick == types.MaxTick {
err := k.updateFullRangeLiquidityInPool(ctx, poolId, liquidity)
if err != nil {
return err
Expand Down Expand Up @@ -413,7 +413,7 @@ func (k Keeper) CreateFullRangePosition(ctx sdk.Context, poolId uint64, owner sd
}

// Create a full range (min to max tick) concentrated liquidity position.
positionData, err := k.CreatePosition(ctx, concentratedPool.GetId(), owner, coins, osmomath.ZeroInt(), osmomath.ZeroInt(), types.MinInitializedTick, types.MaxTick)
positionData, err := k.CreatePosition(ctx, concentratedPool.GetId(), owner, coins, osmomath.ZeroInt(), osmomath.ZeroInt(), types.MinInitializedTickV2, types.MaxTick)
if err != nil {
return types.CreateFullRangePositionData{}, err
}
Expand Down Expand Up @@ -477,7 +477,7 @@ func (k Keeper) mintSharesAndLock(ctx sdk.Context, concentratedPoolId, positionI
if err != nil {
return 0, sdk.Coins{}, err
}
if position.LowerTick != types.MinInitializedTick || position.UpperTick != types.MaxTick {
if position.LowerTick != types.MinInitializedTickV2 || position.UpperTick != types.MaxTick {
return 0, sdk.Coins{}, types.PositionNotFullRangeError{PositionId: positionId, LowerTick: position.LowerTick, UpperTick: position.UpperTick}
}

Expand Down
12 changes: 6 additions & 6 deletions x/concentrated-liquidity/position_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1104,10 +1104,10 @@ func (s *KeeperTestSuite) TestMintSharesAndLock() {
name: "err: upper tick is not max tick",
owner: defaultAddress,
createFullRangePosition: false,
lowerTick: types.MinInitializedTick,
lowerTick: types.MinInitializedTickV2,
upperTick: DefaultUpperTick,
remainingLockDuration: 24 * time.Hour,
expectedErr: types.PositionNotFullRangeError{PositionId: 1, LowerTick: types.MinInitializedTick, UpperTick: DefaultUpperTick},
expectedErr: types.PositionNotFullRangeError{PositionId: 1, LowerTick: types.MinInitializedTickV2, UpperTick: DefaultUpperTick},
},
}

Expand Down Expand Up @@ -1606,7 +1606,7 @@ func (s *KeeperTestSuite) TestGetAndUpdateFullRangeLiquidity() {
{
name: "full range + position overlapping min tick. update liquidity upwards",
positionCoins: sdk.NewCoins(DefaultCoin0, DefaultCoin1),
lowerTick: DefaultMinTick,
lowerTick: types.MinInitializedTickV2,
upperTick: DefaultUpperTick, // max tick doesn't overlap, should not count towards full range liquidity
updateLiquidity: osmomath.NewDec(100),
},
Expand Down Expand Up @@ -1764,7 +1764,7 @@ func (s *KeeperTestSuite) TestCreateFullRangePositionLocked() {
s.Require().NoError(err)
s.Require().Equal(s.Ctx.BlockTime(), position.JoinTime)
s.Require().Equal(types.MaxTick, position.UpperTick)
s.Require().Equal(types.MinInitializedTick, position.LowerTick)
s.Require().Equal(types.MinInitializedTickV2, position.LowerTick)
s.Require().Equal(positionData.Liquidity, position.Liquidity)

// Check locked
Expand Down Expand Up @@ -1926,15 +1926,15 @@ func (s *KeeperTestSuite) TestMultipleRanges() {
},
"one range on min tick": {
tickRanges: [][]int64{
{types.MinInitializedTick, types.MinInitializedTick + 100},
{types.MinInitializedTickV2, types.MinInitializedTickV2 + 100},
},
rangeTestParams: withDoubleFundedLP(DefaultRangeTestParams),
},
"initial current tick equal to min initialized tick": {
tickRanges: [][]int64{
{0, 1},
},
rangeTestParams: withCurrentTick(DefaultRangeTestParams, types.MinInitializedTick),
rangeTestParams: withCurrentTick(DefaultRangeTestParams, types.MinInitializedTickV2),
},
"three overlapping ranges with no swaps, current tick in one": {
tickRanges: [][]int64{
Expand Down
6 changes: 3 additions & 3 deletions x/concentrated-liquidity/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func (k Keeper) GetTickLiquidityForFullRange(ctx sdk.Context, poolId uint64) ([]

// set current tick to min tick, and find the first initialized tick starting from min tick -1.
// we do -1 to make min tick inclusive.
currentTick := types.MinCurrentTick
currentTick := types.MinCurrentTickV2

nextTickIter := swapStrategy.InitializeNextTickIterator(ctx, poolId, currentTick)
defer nextTickIter.Close()
Expand Down Expand Up @@ -137,12 +137,12 @@ func (k Keeper) GetTickLiquidityNetInDirection(ctx sdk.Context, poolId uint64, t

// use max or min tick if provided bound is nil

ctx.Logger().Debug(fmt.Sprintf("min_tick %d\n", types.MinInitializedTick))
ctx.Logger().Debug(fmt.Sprintf("min_tick %d\n", types.MinInitializedTickV2))
ctx.Logger().Debug(fmt.Sprintf("max_tick %d\n", types.MaxTick))

if boundTick.IsNil() {
if zeroForOne {
boundTick = osmomath.NewInt(types.MinInitializedTick)
boundTick = osmomath.NewInt(types.MinInitializedTickV2)
} else {
boundTick = osmomath.NewInt(types.MaxTick)
}
Expand Down
2 changes: 1 addition & 1 deletion x/concentrated-liquidity/simulation/sim_msgs.go
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ func RandomPrepareCreatePositionFunc(sim *osmosimtypes.SimCtx, ctx sdk.Context,
}

// Retrieve minTick and maxTick from kprecision factor
minTick, maxTick := cltypes.MinInitializedTick, cltypes.MaxTick
minTick, maxTick := cltypes.MinInitializedTickV2, cltypes.MaxTick

// Randomize lowerTick and upperTick from max values to create position
lowerTick, upperTick, err := getRandomTickPositions(sim, minTick, maxTick, clPool.GetTickSpacing())
Expand Down
8 changes: 4 additions & 4 deletions x/concentrated-liquidity/spread_rewards_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1375,12 +1375,12 @@ func (s *KeeperTestSuite) TestFunctional_SpreadRewards_Swaps() {
s.CollectAndAssertSpreadRewards(s.Ctx, clPool.GetId(), totalSpreadRewardsExpected, positionIds, [][]int64{ticksActivatedAfterEachSwap}, onlyUSDC, positions)

// Swap multiple times ETH for USDC, therefore decreasing the spot price
ticksActivatedAfterEachSwap, totalSpreadRewardsExpected, _, _ = s.swapAndTrackXTimesInARow(clPool.GetId(), DefaultCoin0, USDC, types.MinSpotPriceBigDec, positions.numSwaps)
ticksActivatedAfterEachSwap, totalSpreadRewardsExpected, _, _ = s.swapAndTrackXTimesInARow(clPool.GetId(), DefaultCoin0, USDC, types.MinSpotPriceV2, positions.numSwaps)
s.CollectAndAssertSpreadRewards(s.Ctx, clPool.GetId(), totalSpreadRewardsExpected, positionIds, [][]int64{ticksActivatedAfterEachSwap}, onlyETH, positions)

// Do the same swaps as before, however this time we collect spread rewards after both swap directions are complete.
ticksActivatedAfterEachSwapUp, totalSpreadRewardsExpectedUp, _, _ := s.swapAndTrackXTimesInARow(clPool.GetId(), DefaultCoin1, ETH, types.MaxSpotPriceBigDec, positions.numSwaps)
ticksActivatedAfterEachSwapDown, totalSpreadRewardsExpectedDown, _, _ := s.swapAndTrackXTimesInARow(clPool.GetId(), DefaultCoin0, USDC, types.MinSpotPriceBigDec, positions.numSwaps)
ticksActivatedAfterEachSwapDown, totalSpreadRewardsExpectedDown, _, _ := s.swapAndTrackXTimesInARow(clPool.GetId(), DefaultCoin0, USDC, types.MinSpotPriceV2, positions.numSwaps)
totalSpreadRewardsExpected = totalSpreadRewardsExpectedUp.Add(totalSpreadRewardsExpectedDown...)

// We expect all positions to have both denoms in their spread reward accumulators except USDC for the overlapping range position since
Expand Down Expand Up @@ -1447,7 +1447,7 @@ func (s *KeeperTestSuite) TestFunctional_SpreadRewards_LP() {
fullLiquidity := positionDataTwo.Liquidity

// Swap once in the other direction.
ticksActivatedAfterEachSwap, totalSpreadRewardsExpected, _, _ = s.swapAndTrackXTimesInARow(pool.GetId(), DefaultCoin0, USDC, types.MinSpotPriceBigDec, 1)
ticksActivatedAfterEachSwap, totalSpreadRewardsExpected, _, _ = s.swapAndTrackXTimesInARow(pool.GetId(), DefaultCoin0, USDC, types.MinSpotPriceV2, 1)

// This should claim under the hood for position 2 since full liquidity is removed.
balanceBeforeWithdraw := s.App.BankKeeper.GetBalance(ctx, owner, ETH)
Expand Down Expand Up @@ -1515,7 +1515,7 @@ func (s *KeeperTestSuite) TestCollectSpreadRewards_MinSpotPriceMigration() {
// Validate that the total spread rewards collected is equal to the expected total spread rewards
s.Require().Equal(len(expectedTotalSpreadRewards), len(actualCollected))
for _, coin := range expectedTotalSpreadRewards {
osmoassert.Equal(s.T(), oneAdditiveTolerance, coin.Amount, actualCollected.AmountOf(coin.Denom))
osmoassert.Equal(s.T(), multiplicativeTolerance, coin.Amount, actualCollected.AmountOf(coin.Denom))
}
}

Expand Down
Loading