Skip to content

Commit

Permalink
refactor: move handlers for reusability
Browse files Browse the repository at this point in the history
  • Loading branch information
johnletey committed Feb 5, 2024
1 parent 06375f8 commit a4baa47
Show file tree
Hide file tree
Showing 2 changed files with 198 additions and 190 deletions.
193 changes: 3 additions & 190 deletions simapp/ante_handler.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
package simapp

import (
"errors"

"github.com/circlefin/noble-fiattokenfactory/x/fiattokenfactory"
fiattokenfactorykeeper "github.com/circlefin/noble-fiattokenfactory/x/fiattokenfactory/keeper"
fiattokenfactorytypes "github.com/circlefin/noble-fiattokenfactory/x/fiattokenfactory/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/bech32"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/auth/ante"
"github.com/cosmos/cosmos-sdk/x/authz"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types"
ibcante "github.com/cosmos/ibc-go/v4/modules/core/ante"
"github.com/cosmos/ibc-go/v4/modules/core/keeper"
)
Expand All @@ -26,187 +20,6 @@ type HandlerOptions struct {
FiatTokenFactoryKeeper *fiattokenfactorykeeper.Keeper
}

type IsPausedDecorator struct {
fiatTokenFactory *fiattokenfactorykeeper.Keeper
}

func NewIsPausedDecorator(ctf *fiattokenfactorykeeper.Keeper) IsPausedDecorator {
return IsPausedDecorator{
fiatTokenFactory: ctf,
}
}

func (ad IsPausedDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
msgs := tx.GetMsgs()

err = ad.CheckMessages(ctx, msgs)
if err != nil {
return ctx, err
}

return next(ctx, tx, simulate)
}

func (ad IsPausedDecorator) CheckMessages(ctx sdk.Context, msgs []sdk.Msg) error {
for _, msg := range msgs {
if execMsg, ok := msg.(*authz.MsgExec); ok {
nestedMsgs, err := execMsg.GetMessages()
if err != nil {
return err
}

return ad.CheckMessages(ctx, nestedMsgs)
}

switch m := msg.(type) {
case *banktypes.MsgSend:
for _, c := range m.Amount {
paused, err := checkPausedStatebyTokenFactory(ctx, c, ad.fiatTokenFactory)
if paused {
return sdkerrors.Wrapf(err, "can not perform token transfers")
}
}
case *banktypes.MsgMultiSend:
for _, i := range m.Inputs {
for _, c := range i.Coins {
paused, err := checkPausedStatebyTokenFactory(ctx, c, ad.fiatTokenFactory)
if paused {
return sdkerrors.Wrapf(err, "can not perform token transfers")
}
}
}
case *transfertypes.MsgTransfer:
paused, err := checkPausedStatebyTokenFactory(ctx, m.Token, ad.fiatTokenFactory)
if paused {
return sdkerrors.Wrapf(err, "can not perform token transfers")
}
default:
continue
}
}

return nil
}

func checkPausedStatebyTokenFactory(ctx sdk.Context, c sdk.Coin, ctf *fiattokenfactorykeeper.Keeper) (bool, *sdkerrors.Error) {
ctfMintingDenom := ctf.GetMintingDenom(ctx)
if c.Denom == ctfMintingDenom.Denom {
paused := ctf.GetPaused(ctx)
if paused.Paused {
return true, fiattokenfactorytypes.ErrPaused
}
}
return false, nil
}

type IsBlacklistedDecorator struct {
fiattokenfactory *fiattokenfactorykeeper.Keeper
}

func NewIsBlacklistedDecorator(ctf *fiattokenfactorykeeper.Keeper) IsBlacklistedDecorator {
return IsBlacklistedDecorator{
fiattokenfactory: ctf,
}
}

func (ad IsBlacklistedDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
msgs := tx.GetMsgs()

err = ad.CheckMessages(ctx, msgs)
if err != nil {
return ctx, err
}

return next(ctx, tx, simulate)
}

func (ad IsBlacklistedDecorator) CheckMessages(ctx sdk.Context, msgs []sdk.Msg) error {
for _, msg := range msgs {
if execMsg, ok := msg.(*authz.MsgExec); ok {
nestedMsgs, err := execMsg.GetMessages()
if err != nil {
return err
}

return ad.CheckMessages(ctx, nestedMsgs)
}

switch m := msg.(type) {
case *banktypes.MsgSend:
for _, c := range m.Amount {
err := checkForBlacklistedAddressByTokenFactory(ctx, m.ToAddress, c, ad.fiattokenfactory)
if errors.Is(err, fiattokenfactorytypes.ErrUnauthorized) {
return sdkerrors.Wrapf(err, "an address (%s) is blacklisted and can not receive tokens", m.ToAddress)
} else if err != nil {
return sdkerrors.Wrapf(err, "error decoding address (%s)", m.ToAddress)
}
err = checkForBlacklistedAddressByTokenFactory(ctx, m.FromAddress, c, ad.fiattokenfactory)
if errors.Is(err, fiattokenfactorytypes.ErrUnauthorized) {
return sdkerrors.Wrapf(err, "an address (%s) is blacklisted and can not send tokens", m.FromAddress)
} else if err != nil {
return sdkerrors.Wrapf(err, "error decoding address (%s)", m.FromAddress)
}
}
case *banktypes.MsgMultiSend:
for _, i := range m.Inputs {
for _, c := range i.Coins {
err := checkForBlacklistedAddressByTokenFactory(ctx, i.Address, c, ad.fiattokenfactory)
if errors.Is(err, fiattokenfactorytypes.ErrUnauthorized) {
return sdkerrors.Wrapf(err, "an address (%s) is blacklisted and can not send or receive tokens", i.Address)
} else if err != nil {
return sdkerrors.Wrapf(err, "error decoding address (%s)", i.Address)
}
}
}
for _, o := range m.Outputs {
for _, c := range o.Coins {
err := checkForBlacklistedAddressByTokenFactory(ctx, o.Address, c, ad.fiattokenfactory)
if errors.Is(err, fiattokenfactorytypes.ErrUnauthorized) {
return sdkerrors.Wrapf(err, "an address (%s) is blacklisted and can not send or receive tokens", o.Address)
} else if err != nil {
return sdkerrors.Wrapf(err, "error decoding address (%s)", o.Address)
}
}
}
case *transfertypes.MsgTransfer:
err := checkForBlacklistedAddressByTokenFactory(ctx, m.Sender, m.Token, ad.fiattokenfactory)
if errors.Is(err, fiattokenfactorytypes.ErrUnauthorized) {
return sdkerrors.Wrapf(err, "an address (%s) is blacklisted and can not send tokens", m.Sender)
} else if err != nil {
return sdkerrors.Wrapf(err, "error decoding address (%s)", m.Sender)
}
err = checkForBlacklistedAddressByTokenFactory(ctx, m.Receiver, m.Token, ad.fiattokenfactory)
if errors.Is(err, fiattokenfactorytypes.ErrUnauthorized) {
return sdkerrors.Wrapf(err, "an address (%s) is blacklisted and can not receive tokens", m.Receiver)
} else if err != nil {
// Ignore the decoding error because the receiver address could be a non-cosmos address and the destination chain should be in charge of minting the token
continue
}
default:
continue
}
}

return nil
}

// checkForBlacklistedAddressByTokenFactory first checks if the denom being transacted is a mintable asset from a TokenFactory,
// if it is, it checks if the address involved in the tx is blacklisted by that specific TokenFactory.
func checkForBlacklistedAddressByTokenFactory(ctx sdk.Context, address string, c sdk.Coin, ctf *fiattokenfactorykeeper.Keeper) error {
ctfMintingDenom := ctf.GetMintingDenom(ctx)
if c.Denom == ctfMintingDenom.Denom {
_, addressBz, err := bech32.DecodeAndConvert(address)
if err != nil {
return err
}
_, found := ctf.GetBlacklisted(ctx, addressBz)
if found {
return fiattokenfactorytypes.ErrUnauthorized
}
}
return nil
}

// NewAnteHandler creates a new ante handler
func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
if options.AccountKeeper == nil {
Expand All @@ -230,8 +43,8 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
anteDecorators := []sdk.AnteDecorator{
ante.NewSetUpContextDecorator(),
ante.NewRejectExtensionOptionsDecorator(),
NewIsBlacklistedDecorator(options.FiatTokenFactoryKeeper),
NewIsPausedDecorator(options.FiatTokenFactoryKeeper),
fiattokenfactory.NewIsBlacklistedDecorator(options.FiatTokenFactoryKeeper),
fiattokenfactory.NewIsPausedDecorator(options.FiatTokenFactoryKeeper),
ante.NewMempoolFeeDecorator(),
ante.NewValidateBasicDecorator(),
ante.NewTxTimeoutHeightDecorator(),
Expand Down
Loading

0 comments on commit a4baa47

Please sign in to comment.