module Tendermint.SDK.Application.AnteHandler ( AnteHandler(..) , applyAnteHandler , baseAppAnteHandler ) where import Control.Monad (unless) import Polysemy import Polysemy.Error (Error) import Tendermint.SDK.BaseApp.Errors (AppError, SDKError (..), throwSDKError) import Tendermint.SDK.BaseApp.Transaction (RoutingTx (..), TransactionApplication) import qualified Tendermint.SDK.Modules.Auth as A import Tendermint.SDK.Types.Message (Msg (..)) import Tendermint.SDK.Types.Transaction (Tx (..)) data AnteHandler r = AnteHandler ( TransactionApplication (Sem r) -> TransactionApplication (Sem r)) instance Semigroup (AnteHandler r) where (<>) (AnteHandler h1) (AnteHandler h2) = AnteHandler $ h1 . h2 instance Monoid (AnteHandler r) where mempty = AnteHandler id applyAnteHandler :: AnteHandler r -> TransactionApplication (Sem r) -> TransactionApplication (Sem r) applyAnteHandler (AnteHandler ah) = ($) ah nonceAnteHandler :: Members A.AuthEffs r => Member (Error AppError) r => AnteHandler r nonceAnteHandler = AnteHandler $ \txApplication tx@(RoutingTx Tx{..}) -> do let Msg{msgAuthor} = txMsg mAcnt <- A.getAccount msgAuthor account <- case mAcnt of Just a@A.Account{accountNonce} -> do unless (accountNonce <= txNonce) $ throwSDKError (NonceException accountNonce txNonce) pure a Nothing -> do unless (txNonce == 0) $ throwSDKError (NonceException 0 txNonce) A.createAccount msgAuthor result <- txApplication tx A.putAccount msgAuthor $ account { A.accountNonce = A.accountNonce account + 1} pure result baseAppAnteHandler :: Members A.AuthEffs r => Member (Error AppError) r => AnteHandler r baseAppAnteHandler = mconcat $ [ nonceAnteHandler ]