Skip to content

Commit

Permalink
F/rewards generation 2 (#62)
Browse files Browse the repository at this point in the history
Thin layer impl of the finalisation block rewards generation. Supersedes
/ replaces #61
  • Loading branch information
maurolacy authored Nov 8, 2024
1 parent 9b24046 commit 47b0a3e
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 16 deletions.
23 changes: 15 additions & 8 deletions x/babylon/contract/in_message.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
package contract

// CustomMsg is a message sent from a smart contract to the Babylon module
// TODO: implement
type CustomMsg struct {
Test *TestMsg `json:"test,omitempty"`
}
import (
wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types"
)

type TestMsg struct {
Placeholder string `json:"placeholder,omitempty"`
}
// CustomMsg is a message sent from a smart contract to the Babylon module
type (
CustomMsg struct {
MintRewards *MintRewardsMsg `json:"mint_rewards,omitempty"`
}
// MintRewardsMsg mints the specified number of block rewards,
// and sends them to the specified recipient (typically, the staking contract)
MintRewardsMsg struct {
Amount wasmvmtypes.Coin `json:"amount"`
Recipient string `json:"recipient"`
}
)
36 changes: 28 additions & 8 deletions x/babylon/keeper/handler_plugin.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package keeper

import (
sdkmath "cosmossdk.io/math"
"encoding/json"

wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper"
wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types"
wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types"
Expand All @@ -22,10 +22,13 @@ type AuthSource interface {
}

// abstract keeper
type msKeeper interface{}
type babylonKeeper interface {
GetParams(ctx sdk.Context) types.Params
MintBlockRewards(ctx sdk.Context, recipient sdk.AccAddress, amount sdk.Coin) (sdkmath.Int, error)
}

type CustomMsgHandler struct {
k msKeeper
k babylonKeeper
auth AuthSource
}

Expand All @@ -36,7 +39,7 @@ func NewDefaultCustomMsgHandler(k *Keeper) *CustomMsgHandler {

// NewCustomMsgHandler constructor to set up CustomMsgHandler with an individual auth source.
// This is an extension point for non default contract authorization logic.
func NewCustomMsgHandler(k msKeeper, auth AuthSource) *CustomMsgHandler {
func NewCustomMsgHandler(k babylonKeeper, auth AuthSource) *CustomMsgHandler {
return &CustomMsgHandler{k: k, auth: auth}
}

Expand All @@ -55,7 +58,7 @@ func (h CustomMsgHandler) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddre
if err := json.Unmarshal(msg.Custom, &customMsg); err != nil {
return nil, nil, nil, sdkerrors.ErrJSONUnmarshal.Wrap("custom message")
}
if customMsg.Test == nil {
if customMsg.MintRewards == nil {
// not our message type
return nil, nil, nil, wasmtypes.ErrUnknownMsg
}
Expand All @@ -64,11 +67,28 @@ func (h CustomMsgHandler) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddre
return nil, nil, nil, sdkerrors.ErrUnauthorized.Wrapf("contract has no permission for Babylon operations")
}

return h.handleTestMsg(ctx, contractAddr, customMsg.Test)
return h.handleMintRewardsMsg(ctx, contractAddr, customMsg.MintRewards)
}

func (h CustomMsgHandler) handleTestMsg(ctx sdk.Context, actor sdk.AccAddress, testMsg *contract.TestMsg) ([]sdk.Event, [][]byte, [][]*codectypes.Any, error) {
return []sdk.Event{}, nil, nil, nil
func (h CustomMsgHandler) handleMintRewardsMsg(ctx sdk.Context, actor sdk.AccAddress, mintMsg *contract.MintRewardsMsg) ([]sdk.Event, [][]byte, [][]*codectypes.Any, error) {
coin, err := wasmkeeper.ConvertWasmCoinToSdkCoin(mintMsg.Amount)
if err != nil {
return nil, nil, nil, err
}
params := h.k.GetParams(ctx)
// Validate actor
if actor.String() != params.BtcFinalityContractAddress {
return nil, nil, nil, sdkerrors.ErrUnauthorized.Wrapf("minter must be the finality contract")
}

// Define recipient
recipient, err := sdk.AccAddressFromBech32(mintMsg.Recipient)
if err != nil {
return nil, nil, nil, err
}

_, err = h.k.MintBlockRewards(ctx, recipient, coin)
return nil, nil, nil, err
}

// AuthSourceFn is helper for simple AuthSource types
Expand Down
56 changes: 56 additions & 0 deletions x/babylon/keeper/mint_rewards.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package keeper

import (
sdkmath "cosmossdk.io/math"
"github.com/babylonlabs-io/babylon-sdk/x/babylon/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/errors"
)

// MintBlockRewards mints new tokens and sends them to the staking contract for distribution.
// Authorization of the actor should be handled before entering this method.
// Authorization of the recipient is being handled within the method for safety, but can
// be removed for flexibility
func (k Keeper) MintBlockRewards(pCtx sdk.Context, recipient sdk.AccAddress, amt sdk.Coin) (sdkmath.Int, error) {
if amt.Amount.IsNil() || amt.Amount.IsZero() || amt.Amount.IsNegative() {
return sdkmath.ZeroInt(), errors.ErrInvalidRequest.Wrap("amount")
}

// Ensure staking constraints
bondDenom, err := k.Staking.BondDenom(pCtx)
if err != nil {
return sdkmath.ZeroInt(), err
}
if amt.Denom != bondDenom {
return sdkmath.ZeroInt(), errors.ErrInvalidRequest.Wrapf("invalid coin denomination: got %s, expected %s", amt.Denom, bondDenom)
}
// FIXME? Remove this constraint for flexibility
params := k.GetParams(pCtx)
if recipient.String() != params.BtcStakingContractAddress {
return sdkmath.ZeroInt(), errors.ErrUnauthorized.Wrapf("invalid recipient: got %s, expected staking contract (%s)",
recipient, params.BtcStakingContractAddress)
}

// TODO?: Ensure Babylon constraints

cacheCtx, done := pCtx.CacheContext() // work in a cached store as Osmosis (safety net?)

// Mint rewards tokens
coins := sdk.NewCoins(amt)
err = k.bank.MintCoins(cacheCtx, types.ModuleName, coins)
if err != nil {
return sdkmath.ZeroInt(), err
}

// FIXME: Confirm we want this supply offset enabled for rewards, i.e.
// as virtual coins that do not count to the total supply
//k.bank.AddSupplyOffset(cacheCtx, bondDenom, amt.Amount.Neg())

err = k.bank.SendCoinsFromModuleToAccount(cacheCtx, types.ModuleName, recipient, coins)
if err != nil {
return sdkmath.ZeroInt(), err
}

done()
return amt.Amount, err
}
1 change: 1 addition & 0 deletions x/babylon/types/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const (
EventTypeMaxCapLimitUpdated = "max_cap_limit_updated"
EventTypeUnbond = "instant_unbond"
EventTypeDelegate = "instant_delegate"
EventTypeMintRewards = "mint_rewards"
)

const (
Expand Down
3 changes: 3 additions & 0 deletions x/babylon/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package types

import (
context "context"
sdkmath "cosmossdk.io/math"

sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
Expand All @@ -18,6 +19,8 @@ type BankKeeper interface {

// StakingKeeper expected staking keeper.
type StakingKeeper interface {
BondDenom(ctx context.Context) (string, error)
StakingTokenSupply(ctx context.Context) (sdkmath.Int, error)
}

// AccountKeeper interface contains functions for getting accounts and the module address
Expand Down

0 comments on commit 47b0a3e

Please sign in to comment.