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

fix: run proto disto on epoch #8106

Merged
merged 5 commits into from
Apr 22, 2024
Merged
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: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### State Breaking

* [#8053](https://github.com/osmosis-labs/osmosis/pull/8053) Reset validator signing info missed blocks counter
* [#8106](https://github.com/osmosis-labs/osmosis/pull/8106) Enable ProtoRev distro on epoch.
* [#8053](https://github.com/osmosis-labs/osmosis/pull/8053) Reset validator signing info missed blocks counter.
* [#8030](https://github.com/osmosis-labs/osmosis/pull/8030) Delete legacy behavior where lockups could not unbond at very small block heights on a testnet.
* [#7005](https://github.com/osmosis-labs/osmosis/pull/7005) Adding deactivated smart account module.

Expand Down
47 changes: 47 additions & 0 deletions x/protorev/keeper/epoch_hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ func (h EpochHooks) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epoch
if h.k.GetProtoRevEnabled(ctx) {
switch epochIdentifier {
case "day":
// Calculate and distribute protorev profits
err := h.CalculateAndDistributeProfits(ctx)
if err != nil {
return err
}

// Increment number of days since module genesis to properly calculate developer fees after cyclic arbitrage trades
if daysSinceGenesis, err := h.k.GetDaysSinceModuleGenesis(ctx); err != nil {
h.k.SetDaysSinceModuleGenesis(ctx, 1)
Expand All @@ -54,6 +60,47 @@ func (h EpochHooks) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epoch
return nil
}

// CalculateAndDistributeProfits is executed after epoch. It gets the current base denom profits and distributes them.
func (h EpochHooks) CalculateAndDistributeProfits(ctx sdk.Context) error {
// Get the current arb profits (only in base denoms to prevent spam vector)
profit, err := h.k.CurrentBaseDenomProfits(ctx)
if err != nil {
return err
}

// Distribute profits to developer account, community pool, and burn osmo
err = h.k.DistributeProfit(ctx, profit)
if err != nil {
return err
}
return nil
}

// CurrentBaseDenomProfits retrieves the current balance of the protorev module account and filters for base denoms.
func (k Keeper) CurrentBaseDenomProfits(ctx sdk.Context) (sdk.Coins, error) {
moduleAcc := k.accountKeeper.GetModuleAddress(types.ModuleName)

baseDenoms, err := k.GetAllBaseDenoms(ctx)
if err != nil {
return nil, err
}

// Get the current protorev balance of all denoms
protorevBalanceAllDenoms := k.bankKeeper.GetAllBalances(ctx, moduleAcc)

// Filter for base denoms
var protorevBalanceBaseDenoms sdk.Coins

for _, baseDenom := range baseDenoms {
amountOfBaseDenom := protorevBalanceAllDenoms.AmountOf(baseDenom.Denom)
if !amountOfBaseDenom.IsZero() {
protorevBalanceBaseDenoms = append(protorevBalanceBaseDenoms, sdk.NewCoin(baseDenom.Denom, amountOfBaseDenom))
}
}

return protorevBalanceBaseDenoms.Sort(), nil
}

// UpdatePools first deletes all of the pools paired with any base denom in the store and then adds the highest liquidity pools that match to the store
func (k Keeper) UpdatePools(ctx sdk.Context) error {
// baseDenomPools maps each base denom to a map of the highest liquidity pools paired with that base denom
Expand Down
111 changes: 111 additions & 0 deletions x/protorev/keeper/epoch_hook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ import (
"strings"
"testing"

sdk "github.com/cosmos/cosmos-sdk/types"
distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types"

"github.com/osmosis-labs/osmosis/osmomath"
"github.com/osmosis-labs/osmosis/v24/app/apptesting"
"github.com/osmosis-labs/osmosis/v24/x/protorev/keeper"
"github.com/osmosis-labs/osmosis/v24/x/protorev/types"
)
Expand Down Expand Up @@ -190,3 +194,110 @@ func contains(baseDenoms []types.BaseDenom, denomToMatch string) bool {
}
return false
}

func (s *KeeperTestSuite) TestAfterEpochEnd() {
tests := []struct {
name string
arbProfits sdk.Coins
}{
{
name: "osmo denom only",
arbProfits: sdk.NewCoins(sdk.NewCoin("uosmo", osmomath.NewInt(100000000))),
},
{
name: "osmo denom and another base denom",
arbProfits: sdk.NewCoins(sdk.NewCoin("uosmo", osmomath.NewInt(100000000)),
sdk.NewCoin("juno", osmomath.NewInt(100000000))),
},
{
name: "osmo denom, another base denom, and a non base denom",
arbProfits: sdk.NewCoins(sdk.NewCoin("uosmo", osmomath.NewInt(100000000)),
sdk.NewCoin("juno", osmomath.NewInt(100000000)),
sdk.NewCoin("eth", osmomath.NewInt(100000000))),
},
{
name: "no profits",
arbProfits: sdk.Coins{},
},
}

for _, tc := range tests {
s.Run(tc.name, func() {
s.SetupPoolsTest()

// Set base denoms
baseDenoms := []types.BaseDenom{
{
Denom: types.OsmosisDenomination,
StepSize: osmomath.NewInt(1_000_000),
},
{
Denom: "juno",
StepSize: osmomath.NewInt(1_000_000),
},
}
s.App.ProtoRevKeeper.SetBaseDenoms(s.Ctx, baseDenoms)

// Set protorev developer account
devAccount := apptesting.CreateRandomAccounts(1)[0]
s.App.ProtoRevKeeper.SetDeveloperAccount(s.Ctx, devAccount)

err := s.App.BankKeeper.MintCoins(s.Ctx, types.ModuleName, tc.arbProfits)
s.Require().NoError(err)

communityPoolBalancePre := s.App.BankKeeper.GetAllBalances(s.Ctx, s.App.AccountKeeper.GetModuleAddress(distrtypes.ModuleName))

// System under test
err = s.App.ProtoRevKeeper.EpochHooks().AfterEpochEnd(s.Ctx, "day", 1)

expectedDevProfit := sdk.Coins{}
expectedOsmoBurn := sdk.Coins{}
arbProfitsBaseDenoms := sdk.Coins{}
arbProfitsNonBaseDenoms := sdk.Coins{}

// Split the profits into base and non base denoms
for _, coin := range tc.arbProfits {
isBaseDenom := false
for _, baseDenom := range baseDenoms {
if coin.Denom == baseDenom.Denom {
isBaseDenom = true
break
}
}
if isBaseDenom {
arbProfitsBaseDenoms = append(arbProfitsBaseDenoms, coin)
} else {
arbProfitsNonBaseDenoms = append(arbProfitsNonBaseDenoms, coin)
}
}
profitSplit := types.ProfitSplitPhase1
for _, arbProfit := range arbProfitsBaseDenoms {
devProfitAmount := arbProfit.Amount.MulRaw(profitSplit).QuoRaw(100)
expectedDevProfit = append(expectedDevProfit, sdk.NewCoin(arbProfit.Denom, devProfitAmount))
}

// Get the developer account balance
devAccountBalance := s.App.BankKeeper.GetAllBalances(s.Ctx, devAccount)
s.Require().Equal(expectedDevProfit, devAccountBalance)

// Get the burn address balance
burnAddressBalance := s.App.BankKeeper.GetAllBalances(s.Ctx, types.DefaultNullAddress)
if arbProfitsBaseDenoms.AmountOf(types.OsmosisDenomination).IsPositive() {
expectedOsmoBurn = sdk.NewCoins(sdk.NewCoin(types.OsmosisDenomination, arbProfitsBaseDenoms.AmountOf(types.OsmosisDenomination).Sub(expectedDevProfit.AmountOf(types.OsmosisDenomination))))
s.Require().Equal(expectedOsmoBurn, burnAddressBalance)
} else {
s.Require().Equal(sdk.Coins{}, burnAddressBalance)
}

// Get the community pool balance
communityPoolBalancePost := s.App.BankKeeper.GetAllBalances(s.Ctx, s.App.AccountKeeper.GetModuleAddress(distrtypes.ModuleName))
actualCommunityPool := communityPoolBalancePost.Sub(communityPoolBalancePre...)
expectedCommunityPool := arbProfitsBaseDenoms.Sub(expectedDevProfit...).Sub(expectedOsmoBurn...)
s.Require().Equal(expectedCommunityPool, actualCommunityPool)

// The protorev module account should only contain the non base denoms if there are any
protorevModuleAccount := s.App.BankKeeper.GetAllBalances(s.Ctx, s.App.AccountKeeper.GetModuleAddress(types.ModuleName))
s.Require().Equal(arbProfitsNonBaseDenoms, protorevModuleAccount)
})
}
}
67 changes: 1 addition & 66 deletions x/protorev/keeper/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,14 @@ import (
"github.com/osmosis-labs/osmosis/osmomath"
gammtypes "github.com/osmosis-labs/osmosis/v24/x/gamm/types"
"github.com/osmosis-labs/osmosis/v24/x/protorev/types"
epochstypes "github.com/osmosis-labs/osmosis/x/epochs/types"
)

type Hooks struct {
k Keeper
}

var (
_ gammtypes.GammHooks = Hooks{}
_ epochstypes.EpochHooks = Hooks{}
_ gammtypes.GammHooks = Hooks{}
)

// Create new ProtoRev hooks.
Expand Down Expand Up @@ -92,24 +90,6 @@ func (h Hooks) AfterConcentratedPoolSwap(ctx sdk.Context, sender sdk.AccAddress,
h.k.StoreSwap(ctx, poolId, input[0].Denom, output[0].Denom)
}

// ----------------------------------------------------------------------------
// EPOCH HOOKS
// ----------------------------------------------------------------------------

// Hooks wrapper struct for incentives keeper

func (h Hooks) BeforeEpochStart(ctx sdk.Context, epochIdentifier string, epochNumber int64) error {
return h.k.BeforeEpochStart(ctx, epochIdentifier, epochNumber)
}

func (h Hooks) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epochNumber int64) error {
return h.k.AfterEpochEnd(ctx, epochIdentifier, epochNumber)
}

func (h Hooks) GetModuleName() string {
return types.ModuleName
}

// ----------------------------------------------------------------------------
// HELPER METHODS
// ----------------------------------------------------------------------------
Expand Down Expand Up @@ -241,48 +221,3 @@ func (k Keeper) CompareAndStorePool(ctx sdk.Context, poolId uint64, baseDenom, o
k.SetPoolForDenomPair(ctx, baseDenom, otherDenom, poolId)
}
}

func (k Keeper) BeforeEpochStart(ctx sdk.Context, epochIdentifier string, epochNumber int64) error {
return nil
}

func (k Keeper) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epochNumber int64) error {
// Get the current arb profits (only in base denoms to prevent spam vector)
profit, err := k.CurrentBaseDenomProfits(ctx)
if err != nil {
return err
}

// Distribute profits to developer account, community pool, and burn osmo
err = k.DistributeProfit(ctx, profit)
if err != nil {
return err
}

return nil
}

// CalculateCurrentProfit retrieves the current balance of the protorev module account and filters for base denoms.
func (k Keeper) CurrentBaseDenomProfits(ctx sdk.Context) (sdk.Coins, error) {
moduleAcc := k.accountKeeper.GetModuleAddress(types.ModuleName)

baseDenoms, err := k.GetAllBaseDenoms(ctx)
if err != nil {
return nil, err
}

// Get the current protorev balance of all denoms
protorevBalanceAllDenoms := k.bankKeeper.GetAllBalances(ctx, moduleAcc)

// Filter for base denoms
var protorevBalanceBaseDenoms sdk.Coins

for _, baseDenom := range baseDenoms {
amountOfBaseDenom := protorevBalanceAllDenoms.AmountOf(baseDenom.Denom)
if !amountOfBaseDenom.IsZero() {
protorevBalanceBaseDenoms = append(protorevBalanceBaseDenoms, sdk.NewCoin(baseDenom.Denom, amountOfBaseDenom))
}
}

return protorevBalanceBaseDenoms.Sort(), nil
}
Loading