Skip to content

Commit

Permalink
configurable route weights
Browse files Browse the repository at this point in the history
  • Loading branch information
davidterpay committed Jan 5, 2023
1 parent 0e5bcd2 commit a129c52
Show file tree
Hide file tree
Showing 9 changed files with 331 additions and 48 deletions.
11 changes: 11 additions & 0 deletions proto/osmosis/protorev/v1beta1/protorev.proto
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,15 @@ message PoolStatistics {
];
// pool_id is the id of the pool
uint64 pool_id = 3;
}

// RouteWeights contains the weights of all of the different route types. Routes
// are broken up into different types based on the pool that is sandwiched in
// between the arbitrage route. This distinction is made and necessary because
// the execution time ranges fairly between the different route types.
message RouteWeights {
// The weight of a route that includes a stableswap pool
uint64 stable_weight = 1;
// The weight of a route that includes a balancer pool
uint64 balancer_weight = 2;
}
16 changes: 14 additions & 2 deletions x/protorev/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,28 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState)
k.SetLatestBlockHeight(ctx, uint64(ctx.BlockHeight()))
k.SetRouteCountForBlock(ctx, 0)

// configure max routes per block (default 100)
// Configure max routes per block. This roughly correlates to the ms of execution time protorev will
// take per block
if err := k.SetMaxRoutesPerBlock(ctx, 100); err != nil {
panic(err)
}

// configure max routes per tx (default 6)
// Configure max routes per tx. This roughly correlates to the ms of execution time protorev will take
// per tx
if err := k.SetMaxRoutesPerTx(ctx, 6); err != nil {
panic(err)
}

// Configure the route weights for genesis. This roughly correlates to the ms of execution time
// by route type
routeWeights := types.RouteWeights{
StableWeight: 5, // it takes around 5 ms to execute a stable swap route
BalancerWeight: 2, // it takes around 2 ms to execute a balancer swap route
}
if err := k.SetRouteWeights(ctx, routeWeights); err != nil {
panic(err)
}

// Update the pools on genesis
if err := k.UpdatePools(ctx); err != nil {
panic(err)
Expand Down
8 changes: 4 additions & 4 deletions x/protorev/keeper/posthandler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func (suite *KeeperTestSuite) TestAnteHandle() {
baseDenomGas: true,
expectedNumOfTrades: sdk.ZeroInt(),
expectedProfits: []*sdk.Coin{},
expectedRouteCount: 2,
expectedRouteCount: 4,
},
expectPass: true,
},
Expand Down Expand Up @@ -110,7 +110,7 @@ func (suite *KeeperTestSuite) TestAnteHandle() {
Amount: sdk.NewInt(24848),
},
},
expectedRouteCount: 3,
expectedRouteCount: 6,
},
expectPass: true,
},
Expand Down Expand Up @@ -146,7 +146,7 @@ func (suite *KeeperTestSuite) TestAnteHandle() {
Amount: sdk.NewInt(24848),
},
},
expectedRouteCount: 4,
expectedRouteCount: 8,
},
expectPass: true,
},
Expand Down Expand Up @@ -182,7 +182,7 @@ func (suite *KeeperTestSuite) TestAnteHandle() {
Amount: sdk.NewInt(56609900),
},
},
expectedRouteCount: 6,
expectedRouteCount: 13,
},
expectPass: true,
},
Expand Down
34 changes: 34 additions & 0 deletions x/protorev/keeper/protorev.go
Original file line number Diff line number Diff line change
Expand Up @@ -380,3 +380,37 @@ func (k Keeper) SetMaxRoutesPerBlock(ctx sdk.Context, maxRoutes uint64) error {

return nil
}

// GetRouteWeights sets the weights of different route types. Route are broken up into different types depending on
// the pool types in the route.
func (k Keeper) GetRouteWeights(ctx sdk.Context) (*types.RouteWeights, error) {
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixRouteWeights)
bz := store.Get(types.KeyPrefixRouteWeights)
if bz == nil {
// This should never happen as it is set to the default value on genesis
return nil, fmt.Errorf("route weights have not been set in state")
}

routeWeights := &types.RouteWeights{}
routeWeights.Unmarshal(bz)

return routeWeights, nil
}

// SetRouteWeights sets the weights of different route types.
func (k Keeper) SetRouteWeights(ctx sdk.Context, routeWeights types.RouteWeights) error {
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixRouteWeights)

if routeWeights.BalancerWeight == 0 || routeWeights.StableWeight == 0 {
return fmt.Errorf("route weights must be greater than 0")
}

bz, err := routeWeights.Marshal()
if err != nil {
return err
}

store.Set(types.KeyPrefixRouteWeights, bz)

return nil
}
18 changes: 18 additions & 0 deletions x/protorev/keeper/protorev_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -362,3 +362,21 @@ func (suite *KeeperTestSuite) TestGetMaxRoutesPerBlock() {
err = suite.App.AppKeepers.ProtoRevKeeper.SetMaxRoutesPerBlock(suite.Ctx, types.MaxIterableRoutesPerBlock+1)
suite.Require().Error(err)
}

// TestGetRouteWeights tests the GetRouteWeights and SetRouteWeights functions.
func (suite *KeeperTestSuite) TestGetRouteWeights() {
// Should be initalized on genesis
routeWeights, err := suite.App.AppKeepers.ProtoRevKeeper.GetRouteWeights(suite.Ctx)
suite.Require().NoError(err)
suite.Require().Equal(types.RouteWeights{StableWeight: 5, BalancerWeight: 2}, *routeWeights)

// Should be able to set the routeWeights
newRouteWeights := types.RouteWeights{
StableWeight: 10,
BalancerWeight: 2,
}
suite.App.AppKeepers.ProtoRevKeeper.SetRouteWeights(suite.Ctx, newRouteWeights)
routeWeights, err = suite.App.AppKeepers.ProtoRevKeeper.GetRouteWeights(suite.Ctx)
suite.Require().NoError(err)
suite.Require().Equal(newRouteWeights, *routeWeights)
}
12 changes: 9 additions & 3 deletions x/protorev/keeper/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ func (k Keeper) GetAndCheckPool(ctx sdk.Context, poolId uint64) (gammtypes.CFMMP
}

// GetRouteWeight retrieves the weight of a route. The weight of a route is determined by the pools that are used in the route.
// If the route includes a stable pool, the weight of the route is 2. Otherwise, the weight of the route is 1.
// Different pools will have different execution times hence the need for a weighted point system.
func (k Keeper) GetRouteWeight(ctx sdk.Context, route swaproutertypes.SwapAmountInRoutes) (uint64, error) {
// Routes must always be of length 3
if route.Length() != 3 {
Expand All @@ -214,11 +214,17 @@ func (k Keeper) GetRouteWeight(ctx sdk.Context, route swaproutertypes.SwapAmount
return 0, err
}

// Get the weights of the route types
routeWeights, err := k.GetRouteWeights(ctx)
if err != nil {
return 0, err
}

switch poolType {
case swaproutertypes.Balancer:
return 1, nil
return routeWeights.BalancerWeight, nil
case swaproutertypes.Stableswap:
return 2, nil
return routeWeights.StableWeight, nil
default:
return 0, fmt.Errorf("invalid pool type")
}
Expand Down
22 changes: 11 additions & 11 deletions x/protorev/keeper/routes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func (suite *KeeperTestSuite) TestBuildRoutes() {
{PoolId: 7, InputDenom: "akash", OutputDenom: types.OsmosisDenomination},
},
},
expectedRouteCount: 2,
expectedRouteCount: 4,
maxIterableRoutes: 15,
},
{
Expand All @@ -52,7 +52,7 @@ func (suite *KeeperTestSuite) TestBuildRoutes() {
{PoolId: 10, InputDenom: "bitcoin", OutputDenom: types.OsmosisDenomination},
},
},
expectedRouteCount: 1,
expectedRouteCount: 2,
maxIterableRoutes: 15,
},
{
Expand All @@ -72,7 +72,7 @@ func (suite *KeeperTestSuite) TestBuildRoutes() {
{PoolId: 4, InputDenom: "bitcoin", OutputDenom: types.AtomDenomination},
},
},
expectedRouteCount: 2,
expectedRouteCount: 4,
maxIterableRoutes: 15,
},
{
Expand All @@ -96,7 +96,7 @@ func (suite *KeeperTestSuite) TestBuildRoutes() {
{PoolId: 30, InputDenom: "busd", OutputDenom: types.OsmosisDenomination},
},
},
expectedRouteCount: 2,
expectedRouteCount: 5,
maxIterableRoutes: 15,
},
{
Expand All @@ -106,7 +106,7 @@ func (suite *KeeperTestSuite) TestBuildRoutes() {
poolID: 29,
expected: [][]TestRoute{},
expectedRouteCount: 0,
maxIterableRoutes: 1,
maxIterableRoutes: 3,
},
{
description: "Two routes exist but only 1 route left to be explored (osmo route chosen)",
Expand All @@ -120,8 +120,8 @@ func (suite *KeeperTestSuite) TestBuildRoutes() {
{PoolId: 10, InputDenom: "bitcoin", OutputDenom: types.OsmosisDenomination},
},
},
expectedRouteCount: 1,
maxIterableRoutes: 1,
expectedRouteCount: 2,
maxIterableRoutes: 2,
},
}

Expand Down Expand Up @@ -163,7 +163,7 @@ func (suite *KeeperTestSuite) TestBuildAtomRoute() {
poolId: 7,
expectedRoute: []TestRoute{{1, types.AtomDenomination, "akash"}, {7, "akash", types.OsmosisDenomination}, {25, types.OsmosisDenomination, types.AtomDenomination}},
hasRoute: true,
expectedRouteCount: 1,
expectedRouteCount: 2,
},
{
description: "Route exists for swap in Akash and swap out Osmo",
Expand All @@ -172,7 +172,7 @@ func (suite *KeeperTestSuite) TestBuildAtomRoute() {
poolId: 7,
expectedRoute: []TestRoute{{25, types.AtomDenomination, types.OsmosisDenomination}, {7, types.OsmosisDenomination, "akash"}, {1, "akash", types.AtomDenomination}},
hasRoute: true,
expectedRouteCount: 1,
expectedRouteCount: 2,
},
{
description: "Route does not exist for swap in Terra and swap out Osmo because the pool does not exist",
Expand Down Expand Up @@ -234,7 +234,7 @@ func (suite *KeeperTestSuite) TestBuildOsmoRoute() {
poolId: 1,
expectedRoute: []TestRoute{{7, types.OsmosisDenomination, "akash"}, {1, "akash", types.AtomDenomination}, {25, types.AtomDenomination, types.OsmosisDenomination}},
hasRoute: true,
expectedRouteCount: 1,
expectedRouteCount: 2,
},
{
description: "Route exists for swap in Akash and swap out Atom",
Expand All @@ -243,7 +243,7 @@ func (suite *KeeperTestSuite) TestBuildOsmoRoute() {
poolId: 1,
expectedRoute: []TestRoute{{25, types.OsmosisDenomination, types.AtomDenomination}, {1, types.AtomDenomination, "akash"}, {7, "akash", types.OsmosisDenomination}},
hasRoute: true,
expectedRouteCount: 1,
expectedRouteCount: 2,
},
{
description: "Route does not exist for swap in Terra and swap out Atom because the pool does not exist",
Expand Down
4 changes: 4 additions & 0 deletions x/protorev/types/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const (
prefixMaxRoutesPerBlock
prefixRouteCountForBlock
prefixLatestBlockHeight
prefixRouteWeights
)

var (
Expand Down Expand Up @@ -87,6 +88,9 @@ var (

// KeyPrefixLatestBlockHeight is the prefix for store that keeps track of the latest recorded block height
KeyPrefixLatestBlockHeight = []byte{prefixLatestBlockHeight}

// KeyPrefixRouteWeights is the prefix for store that keeps track of the weights for different route types
KeyPrefixRouteWeights = []byte{prefixRouteWeights}
)

// Returns the key needed to fetch the osmo pool for a given denom
Expand Down
Loading

0 comments on commit a129c52

Please sign in to comment.