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

[CL Message Audit]: MsgUnlockAndMigrateSharesToFullRangeConcentratedPosition [1/2] #5178

Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -938,8 +938,6 @@ github.com/osmosis-labs/go-mutesting v0.0.0-20221208041716-b43bcd97b3b3 h1:Ylmch
github.com/osmosis-labs/go-mutesting v0.0.0-20221208041716-b43bcd97b3b3/go.mod h1:lV6KnqXYD/ayTe7310MHtM3I2q8Z6bBfMAi+bhwPYtI=
github.com/osmosis-labs/osmosis/osmomath v0.0.3-dev.0.20230503232557-ba905586c111 h1:1ahWbf9iF9sxDOjxrHWFaBGLE0nWFdpiX1pqObUaJO8=
github.com/osmosis-labs/osmosis/osmomath v0.0.3-dev.0.20230503232557-ba905586c111/go.mod h1:a7lhiXRpn8QJ21OhFpaEnUNErTSIafaYpp02q6uI/Dk=
github.com/osmosis-labs/osmosis/osmoutils v0.0.0-20230504190933-b174397f0bc5 h1:fBzTtgZHxvZkpwlg6YtAsNaexEHYaFZDXsYfPQWu9GE=
github.com/osmosis-labs/osmosis/osmoutils v0.0.0-20230504190933-b174397f0bc5/go.mod h1:hk/o9/kmTSZmZqwXcSrPuwj/gpRMCqbE/d3vj6teL2A=
github.com/osmosis-labs/osmosis/osmoutils v0.0.0-20230510161551-8bf252f26bae h1:I1Cy+GpTPWbVi0lBw9+bS1w42YfQjvXNK9bW4YbHhcs=
github.com/osmosis-labs/osmosis/osmoutils v0.0.0-20230510161551-8bf252f26bae/go.mod h1:hk/o9/kmTSZmZqwXcSrPuwj/gpRMCqbE/d3vj6teL2A=
github.com/osmosis-labs/osmosis/x/epochs v0.0.0-20230328024000-175ec88e4304 h1:RIrWLzIiZN5Xd2JOfSOtGZaf6V3qEQYg6EaDTAkMnCo=
Expand Down
4 changes: 2 additions & 2 deletions proto/osmosis/superfluid/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,8 @@ message MsgUnlockAndMigrateSharesToFullRangeConcentratedPosition {
];
// token_out_mins indicates minimum token to exit Balancer pool with.
repeated cosmos.base.v1beta1.Coin token_out_mins = 4 [
(gogoproto.moretags) = "yaml:\"token_out_min_amounts\"",
(gogoproto.nullable) = false
(gogoproto.nullable) = false,
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
czarcas7ic marked this conversation as resolved.
Show resolved Hide resolved
];
}

Expand Down
5 changes: 2 additions & 3 deletions x/gamm/types/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,11 @@ var (
)

func MustGetPoolIdFromShareDenom(denom string) uint64 {
numberStr := strings.TrimLeft(denom, GAMMTokenPrefix)
number, err := strconv.Atoi(numberStr)
number, err := GetPoolIdFromShareDenom(denom)
if err != nil {
panic(err)
}
return uint64(number)
return number
}

func GetPoolIdFromShareDenom(denom string) (uint64, error) {
Expand Down
35 changes: 35 additions & 0 deletions x/superfluid/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,41 @@ It then mints concentrated liquidity shares and locks them up for the
staking duration. From there, the normal superfluid delegation logic
is executed.

### Create Full Range Position and Superfluid Delegate

```{.go}
type MsgUnlockAndMigrateSharesToFullRangeConcentratedPosition struct {
Sender string
LockId uint64
SharesToMigrate sdk.Coin
TokenOutMins sdk.Coins
}
```

Upon completion, the following response is given:

```{.go}
type MsgUnlockAndMigrateSharesToFullRangeConcentratedPositionResponse struct {
Amount0 string
Amount1 string
LiquidityCreated sdk.Dec
JoinTime time.Time
}
```

The message starts by determining which migration method to use.
- If underlying lock is superfluid bonded
- `migrateSuperfluidBondedBalancerToConcentrated`
- If underlying lock is superfluid unbonding
- `migrateSuperfluidUnbondingBalancerToConcentrated`
- If underlying lock is not superfluid bonded (vanilla lock)
- `migrateNonSuperfluidLockBalancerToConcentrated`

It then routes to that migration message, which will migrate the gamm lock from
the previous state it was in, to the same state but in the concentrated pool. If
the sharesToMigrate is zero, then the entire lock is migrated. If only a subset
of the shares are migrated, then the remaining shares are left in the gamm pool.

## Epochs

Overall Epoch sequence
Expand Down
9 changes: 9 additions & 0 deletions x/superfluid/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ func GetTxCmd() *cobra.Command {
)
osmocli.AddTxCmd(cmd, NewCreateFullRangePositionAndSuperfluidDelegateCmd)
osmocli.AddTxCmd(cmd, NewAddToConcentratedLiquiditySuperfluidPositionCmd)
osmocli.AddTxCmd(cmd, NewUnlockAndMigrateSharesToFullRangeConcentratedPositionCmd)

return cmd
}
Expand Down Expand Up @@ -414,3 +415,11 @@ func NewAddToConcentratedLiquiditySuperfluidPositionCmd() (*osmocli.TxCliDesc, *
Example: "add-to-superfluid-cl-position 10 1000000000uosmo 10000000uion",
}, &types.MsgAddToConcentratedLiquiditySuperfluidPosition{}
}

func NewUnlockAndMigrateSharesToFullRangeConcentratedPositionCmd() (*osmocli.TxCliDesc, *types.MsgUnlockAndMigrateSharesToFullRangeConcentratedPosition) {
return &osmocli.TxCliDesc{
Use: "unlock-and-migrate-to-cl [lock-id] [shares-to-migrate] [token-out-mins]",
Short: "unlock and migrate gamm shares to full range concentrated position",
Example: "unlock-and-migrate-cl 10 25000000000gamm/pool/2 1000000000uosmo,10000000uion",
}, &types.MsgUnlockAndMigrateSharesToFullRangeConcentratedPosition{}
}
2 changes: 1 addition & 1 deletion x/superfluid/keeper/concentrated_liquidity.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func (k Keeper) addToConcentratedLiquiditySuperfluidPosition(ctx sdk.Context, ow

// Superfluid undelegate the superfluid delegated position.
// This deletes the connection between the lock and the intermediate account, deletes the synthetic lock, and burns the synthetic osmo.
intermediateAccount, err := k.SuperfluidUndelegateToConcentratedPosition(ctx, owner.String(), lockId)
intermediateAccount, err := k.superfluidUndelegateToConcentratedPosition(ctx, owner.String(), lockId)
if err != nil {
return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, err
}
Expand Down
13 changes: 13 additions & 0 deletions x/superfluid/keeper/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

cltypes "github.com/osmosis-labs/osmosis/v15/x/concentrated-liquidity/types"
lockuptypes "github.com/osmosis-labs/osmosis/v15/x/lockup/types"
"github.com/osmosis-labs/osmosis/v15/x/superfluid/types"
)

var (
Expand Down Expand Up @@ -45,3 +46,15 @@ func (k Keeper) PrepareMigration(ctx sdk.Context, sender sdk.AccAddress, lockId
func (k Keeper) AddToConcentratedLiquiditySuperfluidPosition(ctx sdk.Context, owner sdk.AccAddress, positionId uint64, amount0Added, amount1Added sdk.Int) (uint64, sdk.Int, sdk.Int, sdk.Dec, uint64, error) {
return k.addToConcentratedLiquiditySuperfluidPosition(ctx, owner, positionId, amount0Added, amount1Added)
}

func (k Keeper) SuperfluidUndelegateToConcentratedPosition(ctx sdk.Context, sender string, gammLockID uint64) (types.SuperfluidIntermediaryAccount, error) {
return k.superfluidUndelegateToConcentratedPosition(ctx, sender, gammLockID)
}

func (k Keeper) ValidateGammLockForSuperfluid(ctx sdk.Context, sender sdk.AccAddress, poolId uint64, lockId uint64) (*lockuptypes.PeriodLock, error) {
return k.validateGammLockForSuperfluid(ctx, sender, poolId, lockId)
}

func (k Keeper) GetExistingLockRemainingDuration(ctx sdk.Context, lock *lockuptypes.PeriodLock) (time.Duration, error) {
return k.getExistingLockRemainingDuration(ctx, lock)
}
9 changes: 6 additions & 3 deletions x/superfluid/keeper/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func (k Keeper) migrateSuperfluidBondedBalancerToConcentrated(ctx sdk.Context,

// Superfluid undelegate the superfluid delegated position.
// This deletes the connection between the lock and the intermediate account, deletes the synthetic lock, and burns the synthetic osmo.
intermediateAccount, err := k.SuperfluidUndelegateToConcentratedPosition(ctx, sender.String(), lockId)
intermediateAccount, err := k.superfluidUndelegateToConcentratedPosition(ctx, sender.String(), lockId)
if err != nil {
return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, 0, 0, err
}
Expand Down Expand Up @@ -286,13 +286,16 @@ func (k Keeper) prepareMigration(ctx sdk.Context, sender sdk.AccAddress, lockId
}

// Check that lockID corresponds to sender, and contains correct denomination of LP shares.
preMigrationLock, err = k.validateLockForUnpool(ctx, sender, poolIdLeaving, lockId)
preMigrationLock, err = k.validateGammLockForSuperfluid(ctx, sender, poolIdLeaving, lockId)
if err != nil {
return 0, 0, nil, &lockuptypes.PeriodLock{}, 0, nil, false, false, err
}

// Before we break the lock, we must note the time remaining on the lock.
remainingLockTime = k.getExistingLockRemainingDuration(ctx, preMigrationLock)
remainingLockTime, err = k.getExistingLockRemainingDuration(ctx, preMigrationLock)
if err != nil {
return 0, 0, nil, &lockuptypes.PeriodLock{}, 0, nil, false, false, err
}

// Check if the lock has a corresponding synthetic lock.
// Synthetic lock existence implies that the lock is superfluid delegated or undelegating.
Expand Down
64 changes: 32 additions & 32 deletions x/superfluid/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,38 +132,6 @@ func (server msgServer) LockAndSuperfluidDelegate(goCtx context.Context, msg *ty
}, err
}

func (server msgServer) CreateFullRangePositionAndSuperfluidDelegate(goCtx context.Context, msg *types.MsgCreateFullRangePositionAndSuperfluidDelegate) (*types.MsgCreateFullRangePositionAndSuperfluidDelegateResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

address, err := sdk.AccAddressFromBech32(msg.Sender)
if err != nil {
return &types.MsgCreateFullRangePositionAndSuperfluidDelegateResponse{}, err
}
positionId, _, _, _, _, lockId, err := server.keeper.clk.CreateFullRangePositionLocked(ctx, msg.PoolId, address, msg.Coins, server.keeper.sk.GetParams(ctx).UnbondingTime)
if err != nil {
return &types.MsgCreateFullRangePositionAndSuperfluidDelegateResponse{}, err
}

superfluidDelegateMsg := types.MsgSuperfluidDelegate{
Sender: msg.Sender,
LockId: lockId,
ValAddr: msg.ValAddr,
}

_, err = server.SuperfluidDelegate(goCtx, &superfluidDelegateMsg)

if err != nil {
return &types.MsgCreateFullRangePositionAndSuperfluidDelegateResponse{}, err
}

events.EmitCreateFullRangePositionAndSuperfluidDelegateEvent(ctx, lockId, positionId, msg.ValAddr)

return &types.MsgCreateFullRangePositionAndSuperfluidDelegateResponse{
LockID: lockId,
PositionID: positionId,
}, nil
}

func (server msgServer) UnPoolWhitelistedPool(goCtx context.Context, msg *types.MsgUnPoolWhitelistedPool) (*types.MsgUnPoolWhitelistedPoolResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

Expand Down Expand Up @@ -197,6 +165,38 @@ func (server msgServer) UnPoolWhitelistedPool(goCtx context.Context, msg *types.
return &types.MsgUnPoolWhitelistedPoolResponse{ExitedLockIds: allExitedLockIDs}, nil
}

func (server msgServer) CreateFullRangePositionAndSuperfluidDelegate(goCtx context.Context, msg *types.MsgCreateFullRangePositionAndSuperfluidDelegate) (*types.MsgCreateFullRangePositionAndSuperfluidDelegateResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

address, err := sdk.AccAddressFromBech32(msg.Sender)
if err != nil {
return &types.MsgCreateFullRangePositionAndSuperfluidDelegateResponse{}, err
}
positionId, _, _, _, _, lockId, err := server.keeper.clk.CreateFullRangePositionLocked(ctx, msg.PoolId, address, msg.Coins, server.keeper.sk.GetParams(ctx).UnbondingTime)
if err != nil {
return &types.MsgCreateFullRangePositionAndSuperfluidDelegateResponse{}, err
}

superfluidDelegateMsg := types.MsgSuperfluidDelegate{
Sender: msg.Sender,
LockId: lockId,
ValAddr: msg.ValAddr,
}

_, err = server.SuperfluidDelegate(goCtx, &superfluidDelegateMsg)

if err != nil {
return &types.MsgCreateFullRangePositionAndSuperfluidDelegateResponse{}, err
}

events.EmitCreateFullRangePositionAndSuperfluidDelegateEvent(ctx, lockId, positionId, msg.ValAddr)

return &types.MsgCreateFullRangePositionAndSuperfluidDelegateResponse{
LockID: lockId,
PositionID: positionId,
}, nil
}

func (server msgServer) UnlockAndMigrateSharesToFullRangeConcentratedPosition(goCtx context.Context, msg *types.MsgUnlockAndMigrateSharesToFullRangeConcentratedPosition) (*types.MsgUnlockAndMigrateSharesToFullRangeConcentratedPositionResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

Expand Down
16 changes: 4 additions & 12 deletions x/superfluid/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -473,23 +473,14 @@ func (suite *KeeperTestSuite) TestMsgUnPoolWhitelistedPool_Event() {
func (suite *KeeperTestSuite) TestUnlockAndMigrateSharesToFullRangeConcentratedPosition_Event() {
suite.SetupTest()

const (
token0Denom = "token0"
)

// Update authorized quote denoms with the quote denom relied on by the test
concentratedLiquidityParams := suite.App.ConcentratedLiquidityKeeper.GetParams(suite.Ctx)
concentratedLiquidityParams.AuthorizedQuoteDenoms = append(concentratedLiquidityParams.AuthorizedQuoteDenoms, token0Denom)
suite.App.ConcentratedLiquidityKeeper.SetParams(suite.Ctx, concentratedLiquidityParams)
Comment on lines -476 to -483
Copy link
Member

Choose a reason for hiding this comment

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

Why is this not needed anymore?

Copy link
Member Author

@czarcas7ic czarcas7ic May 15, 2023

Choose a reason for hiding this comment

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

You added this in test_suite.go

s.SetupConcentratedLiquidityDenomsAndPoolCreation()

This auto sets both STAKE and FOO as authorized quote denoms (amoung others) here

func (s *KeeperTestHelper) SetupConcentratedLiquidityDenomsAndPoolCreation() {
// modify authorized quote denoms to include test denoms.
defaultParams := types.DefaultParams()
defaultParams.IsPermissionlessPoolCreationEnabled = true
defaultParams.AuthorizedQuoteDenoms = append(defaultParams.AuthorizedQuoteDenoms, ETH, USDC, BAR, BAZ, FOO, UOSMO, STAKE)
s.App.ConcentratedLiquidityKeeper.SetParams(s.Ctx, defaultParams)
}


msgServer := keeper.NewMsgServerImpl(suite.App.SuperfluidKeeper)
suite.FundAcc(suite.TestAccs[0], defaultAcctFunds)
fullRangeCoins := sdk.NewCoins(defaultPoolAssets[0].Token, defaultPoolAssets[1].Token)

// Set validators
valAddrs := suite.SetupValidators([]stakingtypes.BondStatus{stakingtypes.Bonded})

// Set balancer pool and make its respective gamm share an authorized superfluid asset
// Set balancer pool (foo and stake) and make its respective gamm share an authorized superfluid asset
msg := balancer.NewMsgCreateBalancerPool(suite.TestAccs[0], balancer.PoolParams{
SwapFee: sdk.NewDecWithPrec(1, 2),
ExitFee: sdk.NewDec(0),
Expand All @@ -505,7 +496,7 @@ func (suite *KeeperTestSuite) TestUnlockAndMigrateSharesToFullRangeConcentratedP
})
suite.Require().NoError(err)

// Set concentrated pool with the same denoms as the balancer pool
// Set concentrated pool with the same denoms as the balancer pool (foo and stake)
clPool := suite.PrepareCustomConcentratedPool(suite.TestAccs[0], defaultPoolAssets[0].Token.Denom, defaultPoolAssets[1].Token.Denom, 1, sdk.ZeroDec())

// Set migration link between the balancer and concentrated pool
Expand All @@ -529,7 +520,8 @@ func (suite *KeeperTestSuite) TestUnlockAndMigrateSharesToFullRangeConcentratedP
suite.Require().NoError(err)

// Execute UnlockAndMigrateSharesToFullRangeConcentratedPosition message
sender, _ := sdk.AccAddressFromBech32(locks[0].Owner)
sender, err := sdk.AccAddressFromBech32(locks[0].Owner)
suite.Require().NoError(err)
_, err = msgServer.UnlockAndMigrateSharesToFullRangeConcentratedPosition(sdk.WrapSDKContext(suite.Ctx),
types.NewMsgUnlockAndMigrateSharesToFullRangeConcentratedPosition(sender, locks[0].ID, locks[0].Coins[0]))
suite.Require().NoError(err)
Expand Down
6 changes: 3 additions & 3 deletions x/superfluid/keeper/stake.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ func (k Keeper) SuperfluidDelegate(ctx sdk.Context, sender string, lockID uint64
return k.mintOsmoTokensAndDelegate(ctx, amount, acc)
}

// undelegateCommon is a helper function for SuperfluidUndelegate and SuperfluidUndelegateToConcentratedPosition.
// undelegateCommon is a helper function for SuperfluidUndelegate and superfluidUndelegateToConcentratedPosition.
// It performs the following tasks:
// - checks that the lock is valid for superfluid staking
// - gets the intermediary account associated with the lock id
Expand Down Expand Up @@ -300,10 +300,10 @@ func (k Keeper) SuperfluidUndelegate(ctx sdk.Context, sender string, lockID uint
return k.createSyntheticLockup(ctx, lockID, intermediaryAcc, unlockingStatus)
}

// SuperfluidUndelegateToConcentratedPosition starts undelegating superfluid delegated position for the given lock. It behaves similarly to SuperfluidUndelegate,
// superfluidUndelegateToConcentratedPosition starts undelegating superfluid delegated position for the given lock. It behaves similarly to SuperfluidUndelegate,
// however it does not create a new synthetic lockup representing the unstaking side. This is because at the time this function is called, the new concentrated liquidity side
// lock has not yet been created. Once the new cl side lock is created, the synthetic lockup representing the unstaking side is created.
func (k Keeper) SuperfluidUndelegateToConcentratedPosition(ctx sdk.Context, sender string, gammLockID uint64) (types.SuperfluidIntermediaryAccount, error) {
func (k Keeper) superfluidUndelegateToConcentratedPosition(ctx sdk.Context, sender string, gammLockID uint64) (types.SuperfluidIntermediaryAccount, error) {
return k.undelegateCommon(ctx, sender, gammLockID)
}

Expand Down
42 changes: 27 additions & 15 deletions x/superfluid/keeper/unpool.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,17 @@ func (k Keeper) UnpoolAllowedPools(ctx sdk.Context, sender sdk.AccAddress, poolI
// 2) Consistency check that lockID corresponds to sender, and contains correct LP shares.
// These are expected to be true by the caller, but good to double check
// TODO: Try to minimize dependence on lock here
lock, err := k.validateLockForUnpool(ctx, sender, poolId, lockId)
lock, err := k.validateGammLockForSuperfluid(ctx, sender, poolId, lockId)
if err != nil {
return []uint64{}, err
}
gammSharesInLock := lock.Coins[0]

// 3) Get remaining duration on the lock. Handle if the lock was unbonding.
lockRemainingDuration := k.getExistingLockRemainingDuration(ctx, lock)
lockRemainingDuration, err := k.getExistingLockRemainingDuration(ctx, lock)
if err != nil {
return []uint64{}, err
}

// 4) If superfluid delegated, superfluid undelegate
err = k.unbondSuperfluidIfExists(ctx, sender, lockId)
Expand Down Expand Up @@ -99,39 +102,48 @@ func (k Keeper) checkUnpoolWhitelisted(ctx sdk.Context, poolId uint64) error {
return types.ErrPoolNotWhitelisted
}

// check if pool is whitelisted for unpool
func (k Keeper) validateLockForUnpool(ctx sdk.Context, sender sdk.AccAddress, poolId uint64, lockId uint64) (*lockuptypes.PeriodLock, error) {
// validateGammLockForSuperfluid checks if the provided lock:
// 1) is owned by the provided sender
// 2) contains only 1 coin
// 3) contains the gamm LP shares associated with the provided poolId
func (k Keeper) validateGammLockForSuperfluid(ctx sdk.Context, sender sdk.AccAddress, poolId uint64, lockId uint64) (*lockuptypes.PeriodLock, error) {
Copy link
Member

Choose a reason for hiding this comment

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

by superfluid, are you referring to validating the lock and making sure it can be superfluid staked? If so, consider changing to validateGammLockForSuperfluidStaking

Copy link
Member

Choose a reason for hiding this comment

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

I am a little worried that the new name might be misleading since that just because a lock has met the conditions below, it does not mean that it is safe to be superfluid staked 🤔

Copy link
Member Author

Choose a reason for hiding this comment

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

Other than being whitelisted, what other checks need to happen to make a lock safe for superfluid staking? It feels like if the above checks are valid the lock is safe for superfluid staking (given it is whitelisted)

Copy link
Member Author

Choose a reason for hiding this comment

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

Renamed it to validateGammLockForSuperfluidStaking here f8756cd

lock, err := k.lk.GetLockByID(ctx, lockId)
if err != nil {
return lock, err
return &lockuptypes.PeriodLock{}, err
}

// consistency check: validate lock owner
// However, we expect this to be guaranteed by caller though.
// Validate lock owner.
// We expect this to be guaranteed by caller, though.
if lock.Owner != sender.String() {
return lock, lockuptypes.ErrNotLockOwner
return &lockuptypes.PeriodLock{}, lockuptypes.ErrNotLockOwner
}

if lock.Coins.Len() != 1 {
return lock, types.ErrMultipleCoinsLockupNotSupported
return &lockuptypes.PeriodLock{}, types.ErrMultipleCoinsLockupNotSupported
}

gammShare := lock.Coins[0]
if gammShare.Denom != gammtypes.GetPoolShareDenom(poolId) {
return lock, types.ErrLockUnpoolNotAllowed
return &lockuptypes.PeriodLock{}, types.UnexpectedDenomError{ExpectedDenom: gammtypes.GetPoolShareDenom(poolId), ProvidedDenom: gammShare.Denom}
}

return lock, nil
}

func (k Keeper) getExistingLockRemainingDuration(ctx sdk.Context, lock *lockuptypes.PeriodLock) time.Duration {
// getExistingLockRemainingDuration returns the time remaining until the lock is finished unlocking.
// If the lock is not unlocking, then the duration field of the lock is returned.
func (k Keeper) getExistingLockRemainingDuration(ctx sdk.Context, lock *lockuptypes.PeriodLock) (time.Duration, error) {
if lock.IsUnlocking() {
// lock is unlocking, so remaining duration equals lock.EndTime - ctx.BlockTime
// Lock is unlocking, so remaining duration equals lock.EndTime - ctx.BlockTime.
remainingDuration := lock.EndTime.Sub(ctx.BlockTime())
return remainingDuration
// Defense in depth, ensure the duration is not negative.
if remainingDuration < 0 {
return 0, types.NegativeDurationError{Duration: remainingDuration}
}
return remainingDuration, nil
}
// lock is bonded, thus the time it should take to unlock is lock.Duration
return lock.Duration
// Lock is not unlocking, thus the time it should take to unlock is the locks duration.
return lock.Duration, nil
}

// TODO: Review this in more depth
Expand Down
Loading