Skip to content

Commit

Permalink
feat: add pool address
Browse files Browse the repository at this point in the history
  • Loading branch information
RiccardoM committed Jun 13, 2024
1 parent 9fbb518 commit 55d091e
Show file tree
Hide file tree
Showing 17 changed files with 183 additions and 34 deletions.
1 change: 1 addition & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,7 @@ func NewMilkyWayApp(
app.PoolsKeeper = poolskeeper.NewKeeper(
app.appCodec,
keys[poolstypes.StoreKey],
app.AccountKeeper,
)

/**** Module Options ****/
Expand Down
4 changes: 4 additions & 0 deletions proto/milkyway/pools/v1/models.proto
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,8 @@ message Pool {

// Denom represents the denomination of the tokens that are staked in the pool
string denom = 2;

// Address represents the address of the account that is associated with this
// pool. This will be used to store tokens that users delegate to this pool.
string address = 3 [ (cosmos_proto.scalar) = "cosmos.AddressString" ];
}
3 changes: 2 additions & 1 deletion proto/milkyway/pools/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ message QueryPoolByIdRequest {
uint32 pool_id = 1;
}

// QueryPoolByDenomRequest is the request type for the Query/PollByDenom RPC method.
// QueryPoolByDenomRequest is the request type for the Query/PollByDenom RPC
// method.
message QueryPoolByDenomRequest {
// Denom is the denom for which the pool is to be queried
string denom = 1;
Expand Down
14 changes: 13 additions & 1 deletion x/pools/keeper/alias_functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,20 @@ package keeper

import (
storetypes "cosmossdk.io/store/types"
"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/milkyway-labs/milkyway/x/pools/types"
)

// createAccountIfNotExists creates an account if it does not exist
func (k *Keeper) createAccountIfNotExists(ctx sdk.Context, address sdk.AccAddress) {
if !k.accountKeeper.HasAccount(ctx, address) {
defer telemetry.IncrCounter(1, "new", "account")
k.accountKeeper.SetAccount(ctx, k.accountKeeper.NewAccountWithAddress(ctx, address))
}
}

// IteratePools iterates over the pools in the store and performs a callback function
func (k *Keeper) IteratePools(ctx sdk.Context, cb func(pool types.Pool) (stop bool)) {
store := ctx.KVStore(k.storeKey)
Expand Down Expand Up @@ -75,7 +84,10 @@ func (k *Keeper) CreateOrGetPoolByDenom(ctx sdk.Context, denom string) (types.Po
}

// Save the pool
k.SavePool(ctx, pool)
err = k.SavePool(ctx, pool)
if err != nil {
return types.Pool{}, err
}

// Increment the pool id
k.SetNextPoolID(ctx, poolID+1)
Expand Down
6 changes: 4 additions & 2 deletions x/pools/keeper/alias_functions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ func (suite *KeeperTestSuite) TestKeeper_GetPoolForDenom() {
{
name: "existing pool is returned properly",
store: func(ctx sdk.Context) {
suite.k.SavePool(ctx, types.NewPool(1, "umilk"))
err := suite.k.SavePool(ctx, types.NewPool(1, "umilk"))
suite.Require().NoError(err)
},
denom: "umilk",
expFound: true,
Expand Down Expand Up @@ -82,7 +83,8 @@ func (suite *KeeperTestSuite) TestKeeper_CreateOrGetPoolByDenom() {
{
name: "existing pool is returned properly",
store: func(ctx sdk.Context) {
suite.k.SavePool(ctx, types.NewPool(1, "umilk"))
err := suite.k.SavePool(ctx, types.NewPool(1, "umilk"))
suite.Require().NoError(err)
},
denom: "umilk",
shouldErr: false,
Expand Down
1 change: 1 addition & 0 deletions x/pools/keeper/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,6 @@ func (suite *KeeperTestSuite) SetupTest() {
suite.k = keeper.NewKeeper(
suite.cdc,
suite.storeKey,
suite.ak,
)
}
5 changes: 4 additions & 1 deletion x/pools/keeper/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ func (k *Keeper) InitGenesis(ctx sdk.Context, data *types.GenesisState) {

// Store the pools
for _, pool := range data.Pools {
k.SavePool(ctx, pool)
err := k.SavePool(ctx, pool)
if err != nil {
panic(err)
}
}
}
7 changes: 5 additions & 2 deletions x/pools/keeper/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@ func (suite *KeeperTestSuite) TestKeeper_ExportGenesis() {
name: "pools are exported properly",
store: func(ctx sdk.Context) {
suite.k.SetNextPoolID(ctx, 1)
suite.k.SavePool(ctx, types.NewPool(1, "umilk"))
suite.k.SavePool(ctx, types.NewPool(2, "uatom"))

err := suite.k.SavePool(ctx, types.NewPool(1, "umilk"))
suite.Require().NoError(err)
err = suite.k.SavePool(ctx, types.NewPool(2, "uatom"))
suite.Require().NoError(err)
},
expGenesis: &types.GenesisState{
NextPoolID: 1,
Expand Down
6 changes: 4 additions & 2 deletions x/pools/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ func (suite *KeeperTestSuite) TestQueryServer_PoolById() {
{
name: "found pool is returned properly",
store: func(ctx sdk.Context) {
suite.k.SavePool(ctx, types.NewPool(1, "umilk"))
err := suite.k.SavePool(ctx, types.NewPool(1, "umilk"))
suite.Require().NoError(err)
},
request: &types.QueryPoolByIdRequest{
PoolId: 1,
Expand Down Expand Up @@ -76,7 +77,8 @@ func (suite *KeeperTestSuite) TestQueryServer_PoolByDenom() {
{
name: "found pool is returned properly",
store: func(ctx sdk.Context) {
suite.k.SavePool(ctx, types.NewPool(1, "umilk"))
err := suite.k.SavePool(ctx, types.NewPool(1, "umilk"))
suite.Require().NoError(err)
},
request: &types.QueryPoolByDenomRequest{
Denom: "umilk",
Expand Down
19 changes: 13 additions & 6 deletions x/pools/keeper/invariants_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,40 +17,47 @@ func (suite *KeeperTestSuite) TestValidPoolsInvariant() {
{
name: "not found next service id breaks invariant",
store: func(ctx sdk.Context) {
suite.k.SavePool(ctx, types.NewPool(1, "umilk"))
err := suite.k.SavePool(ctx, types.NewPool(1, "umilk"))
suite.Require().NoError(err)
},
expBroken: true,
},
{
name: "service with id equals to next service id breaks invariant",
store: func(ctx sdk.Context) {
suite.k.SetNextPoolID(ctx, 1)
suite.k.SavePool(ctx, types.NewPool(1, "umilk"))
err := suite.k.SavePool(ctx, types.NewPool(1, "umilk"))
suite.Require().NoError(err)
},
expBroken: true,
},
{
name: "service with id higher than next service id breaks invariant",
store: func(ctx sdk.Context) {
suite.k.SetNextPoolID(ctx, 1)
suite.k.SavePool(ctx, types.NewPool(2, "umilk"))
err := suite.k.SavePool(ctx, types.NewPool(2, "umilk"))
suite.Require().NoError(err)
},
expBroken: true,
},
{
name: "invalid service breaks invariant",
store: func(ctx sdk.Context) {
suite.k.SetNextPoolID(ctx, 2)
suite.k.SavePool(ctx, types.NewPool(1, "invalid!"))
err := suite.k.SavePool(ctx, types.NewPool(1, "invalid!"))
suite.Require().NoError(err)
},
expBroken: true,
},
{
name: "valid data does not break invariant",
store: func(ctx sdk.Context) {
suite.k.SetNextPoolID(ctx, 3)
suite.k.SavePool(ctx, types.NewPool(1, "umilk"))
suite.k.SavePool(ctx, types.NewPool(2, "unit"))

err := suite.k.SavePool(ctx, types.NewPool(1, "umilk"))
suite.Require().NoError(err)
err = suite.k.SavePool(ctx, types.NewPool(2, "unit"))
suite.Require().NoError(err)
},
expBroken: false,
},
Expand Down
9 changes: 6 additions & 3 deletions x/pools/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,15 @@ import (
type Keeper struct {
storeKey storetypes.StoreKey
cdc codec.Codec

accountKeeper types.AccountKeeper
}

func NewKeeper(cdc codec.Codec, storeKey storetypes.StoreKey) *Keeper {
func NewKeeper(cdc codec.Codec, storeKey storetypes.StoreKey, accountKeeper types.AccountKeeper) *Keeper {
return &Keeper{
storeKey: storeKey,
cdc: cdc,
storeKey: storeKey,
cdc: cdc,
accountKeeper: accountKeeper,
}
}

Expand Down
12 changes: 11 additions & 1 deletion x/pools/keeper/pools.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package keeper
import (
"cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"

"github.com/milkyway-labs/milkyway/x/pools/types"
)
Expand All @@ -28,9 +29,18 @@ func (k *Keeper) GetNextPoolID(ctx sdk.Context) (serviceID uint32, err error) {
// --------------------------------------------------------------------------------------------------------------------

// SavePool stores the given pool inside the store
func (k *Keeper) SavePool(ctx sdk.Context, pool types.Pool) {
func (k *Keeper) SavePool(ctx sdk.Context, pool types.Pool) error {
store := ctx.KVStore(k.storeKey)
store.Set(types.GetPoolStoreKey(pool.ID), k.cdc.MustMarshal(&pool))

// Create the pool account if it does not exist
poolAddress, err := sdk.AccAddressFromBech32(pool.Address)
if err != nil {
return errors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid pool address: %s", pool.Address)
}
k.createAccountIfNotExists(ctx, poolAddress)

return nil
}

// GetPool retrieves the pool with the given ID from the store.
Expand Down
28 changes: 23 additions & 5 deletions x/pools/keeper/pools_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,25 +107,37 @@ func (suite *KeeperTestSuite) TestKeeper_SavePool() {
store: func(ctx sdk.Context) {
suite.k.SetNextPoolID(ctx, 1)
},
shouldErr: true,
shouldErr: false,
pool: types.NewPool(1, "uatom"),
check: func(ctx sdk.Context) {
// Make sure the pool is saved properly
pool, found := suite.k.GetPool(ctx, 1)
suite.Require().True(found)
suite.Require().Equal(types.NewPool(1, "uatom"), pool)

// Make sure the pool account is created
hasAccount := suite.ak.HasAccount(ctx, types.GetPoolAddress(1))
suite.Require().True(hasAccount)
},
},
{
name: "existing pool is overridden properly",
setup: func() {
suite.k.SetNextPoolID(suite.ctx, 1)
suite.k.SavePool(suite.ctx, types.NewPool(1, "uatom"))
err := suite.k.SavePool(suite.ctx, types.NewPool(1, "uatom"))
suite.Require().NoError(err)
},
pool: types.NewPool(1, "usdt"),
pool: types.NewPool(1, "usdt"),
shouldErr: false,
check: func(ctx sdk.Context) {
// Make sure the pool is saved properly
pool, found := suite.k.GetPool(ctx, 1)
suite.Require().True(found)
suite.Require().Equal(types.NewPool(1, "usdt"), pool)

// Make sure the pool account is created
hasAccount := suite.ak.HasAccount(ctx, types.GetPoolAddress(1))
suite.Require().True(hasAccount)
},
},
}
Expand All @@ -141,7 +153,12 @@ func (suite *KeeperTestSuite) TestKeeper_SavePool() {
tc.store(ctx)
}

suite.k.SavePool(ctx, tc.pool)
err := suite.k.SavePool(ctx, tc.pool)
if tc.shouldErr {
suite.Require().Error(err)
} else {
suite.Require().NoError(err)
}

if tc.check != nil {
tc.check(ctx)
Expand All @@ -168,7 +185,8 @@ func (suite *KeeperTestSuite) TestKeeper_GetPool() {
{
name: "found pool is returned properly",
store: func(ctx sdk.Context) {
suite.k.SavePool(ctx, types.NewPool(1, "uatom"))
err := suite.k.SavePool(ctx, types.NewPool(1, "uatom"))
suite.Require().NoError(err)
},
poolID: 1,
expFound: true,
Expand Down
13 changes: 13 additions & 0 deletions x/pools/types/expected_keepers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package types

import (
"context"

sdk "github.com/cosmos/cosmos-sdk/types"
)

type AccountKeeper interface {
NewAccountWithAddress(ctx context.Context, addr sdk.AccAddress) sdk.AccountI
HasAccount(ctx context.Context, addr sdk.AccAddress) bool
SetAccount(ctx context.Context, acc sdk.AccountI)
}
16 changes: 14 additions & 2 deletions x/pools/types/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,14 @@ import (
"strconv"

sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
)

// GetPoolAddress generates a pool address from its id
func GetPoolAddress(poolID uint32) sdk.AccAddress {
return authtypes.NewModuleAddress(fmt.Sprintf("pool-%d", poolID))
}

// ParsePoolID parses a pool id from a string
func ParsePoolID(value string) (uint32, error) {
parsed, err := strconv.ParseUint(value, 10, 32)
Expand All @@ -21,8 +27,9 @@ func ParsePoolID(value string) (uint32, error) {
// NewPool creates a new Pool instance
func NewPool(id uint32, denom string) Pool {
return Pool{
ID: id,
Denom: denom,
ID: id,
Denom: denom,
Address: GetPoolAddress(id).String(),
}
}

Expand All @@ -36,5 +43,10 @@ func (p *Pool) Validate() error {
return fmt.Errorf("invalid pool denom")
}

_, err := sdk.AccAddressFromBech32(p.Address)
if err != nil {
return fmt.Errorf("invalid pool address")
}

return nil
}
Loading

0 comments on commit 55d091e

Please sign in to comment.