{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE UndecidableInstances #-}
module Convex.Devnet.Wallet(
faucet,
sendFaucetFundsTo,
createSeededWallet,
walletUtxos,
balanceAndSubmit,
balanceAndSubmitReturn,
WalletLog(..),
TracerMonadLogT(..),
runTracerMonadLogT,
runningNodeBlockchain
) where
import Cardano.Api (AddressInEra, BabbageEra, BuildTx,
Lovelace, Tx, TxBodyContent)
import qualified Cardano.Api as C
import Control.Monad (replicateM)
import Control.Monad.IO.Class (MonadIO (..))
import Control.Monad.Reader (ReaderT (..), ask, lift)
import Control.Tracer (Tracer, traceWith)
import qualified Convex.BuildTx as BuildTx
import Convex.Class (MonadBlockchain (networkId),
runMonadBlockchainCardanoNodeT,
sendTx)
import qualified Convex.CoinSelection as CoinSelection
import Convex.Devnet.CardanoNode (RunningNode (..))
import qualified Convex.Devnet.NodeQueries as NodeQueries
import Convex.Devnet.Utils (keysFor)
import Convex.Lenses (emptyTxOut)
import Convex.MonadLog (MonadLog (..))
import Convex.Utxos (UtxoSet)
import qualified Convex.Utxos as Utxos
import Convex.Wallet (Wallet (..), address)
import qualified Convex.Wallet as Wallet
import Data.Aeson (FromJSON, ToJSON)
import Data.Text (Text)
import GHC.Generics (Generic)
import Prettyprinter (defaultLayoutOptions, layoutPretty)
import qualified Prettyprinter.Render.Text as Render
faucet :: IO Wallet
faucet :: IO Wallet
faucet = SigningKey PaymentKey -> Wallet
Wallet forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> b
snd forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> IO (VerificationKey PaymentKey, SigningKey PaymentKey)
keysFor String
"faucet"
walletUtxos :: RunningNode -> Wallet -> IO (UtxoSet C.CtxUTxO ())
walletUtxos :: RunningNode -> Wallet -> IO (UtxoSet CtxUTxO ())
walletUtxos RunningNode{String
rnNodeSocket :: RunningNode -> String
rnNodeSocket :: String
rnNodeSocket, NetworkId
rnNetworkId :: RunningNode -> NetworkId
rnNetworkId :: NetworkId
rnNetworkId} Wallet
wllt =
UTxO BabbageEra -> UtxoSet CtxUTxO ()
Utxos.fromApiUtxo forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> NetworkId
-> String -> [Address ShelleyAddr] -> IO (UTxO BabbageEra)
NodeQueries.queryUTxO NetworkId
rnNetworkId String
rnNodeSocket [NetworkId -> Wallet -> Address ShelleyAddr
address NetworkId
rnNetworkId Wallet
wllt]
sendFaucetFundsTo :: Tracer IO WalletLog -> RunningNode -> AddressInEra BabbageEra -> Int -> Lovelace -> IO (Tx BabbageEra)
sendFaucetFundsTo :: Tracer IO WalletLog
-> RunningNode
-> AddressInEra BabbageEra
-> Int
-> Lovelace
-> IO (Tx BabbageEra)
sendFaucetFundsTo Tracer IO WalletLog
tracer RunningNode
node AddressInEra BabbageEra
destination Int
n Lovelace
amount = do
Wallet
fct <- IO Wallet
faucet
Tracer IO WalletLog
-> RunningNode
-> Wallet
-> TxBodyContent BuildTx BabbageEra
-> IO (Tx BabbageEra)
balanceAndSubmit Tracer IO WalletLog
tracer RunningNode
node Wallet
fct forall a b. (a -> b) -> a -> b
$ forall a. BuildTxT Identity a -> TxBodyContent BuildTx BabbageEra
BuildTx.execBuildTx' forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. Applicative m => Int -> m a -> m [a]
replicateM Int
n (forall (m :: * -> *).
MonadBuildTx m =>
AddressInEra BabbageEra -> Value -> m ()
BuildTx.payToAddress AddressInEra BabbageEra
destination (Lovelace -> Value
C.lovelaceToValue Lovelace
amount))
createSeededWallet :: Tracer IO WalletLog -> RunningNode -> Int -> Lovelace -> IO Wallet
createSeededWallet :: Tracer IO WalletLog -> RunningNode -> Int -> Lovelace -> IO Wallet
createSeededWallet Tracer IO WalletLog
tracer node :: RunningNode
node@RunningNode{NetworkId
rnNetworkId :: NetworkId
rnNetworkId :: RunningNode -> NetworkId
rnNetworkId, String
rnNodeSocket :: String
rnNodeSocket :: RunningNode -> String
rnNodeSocket} Int
n Lovelace
amount = do
Wallet
wallet <- IO Wallet
Wallet.generateWallet
forall (m :: * -> *) a. Tracer m a -> a -> m ()
traceWith Tracer IO WalletLog
tracer (Wallet -> WalletLog
GeneratedWallet Wallet
wallet)
Tracer IO WalletLog
-> RunningNode
-> AddressInEra BabbageEra
-> Int
-> Lovelace
-> IO (Tx BabbageEra)
sendFaucetFundsTo Tracer IO WalletLog
tracer RunningNode
node (forall era.
IsShelleyBasedEra era =>
NetworkId -> Wallet -> AddressInEra era
Wallet.addressInEra NetworkId
rnNetworkId Wallet
wallet) Int
n Lovelace
amount forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= NetworkId -> String -> Tx BabbageEra -> IO ()
NodeQueries.waitForTxn NetworkId
rnNetworkId String
rnNodeSocket
forall (f :: * -> *) a. Applicative f => a -> f a
pure Wallet
wallet
runningNodeBlockchain ::
forall e a. (Show e)
=> Tracer IO WalletLog
-> RunningNode
-> (forall m. (MonadFail m, MonadLog m, MonadBlockchain m) => m a)
-> IO a
runningNodeBlockchain :: forall e a.
Show e =>
Tracer IO WalletLog
-> RunningNode
-> (forall (m :: * -> *).
(MonadFail m, MonadLog m, MonadBlockchain m) =>
m a)
-> IO a
runningNodeBlockchain Tracer IO WalletLog
tracer RunningNode{String
rnNodeSocket :: String
rnNodeSocket :: RunningNode -> String
rnNodeSocket, NetworkId
rnNetworkId :: NetworkId
rnNetworkId :: RunningNode -> NetworkId
rnNetworkId} forall (m :: * -> *).
(MonadFail m, MonadLog m, MonadBlockchain m) =>
m a
h =
let info :: LocalNodeConnectInfo CardanoMode
info = NetworkId -> String -> LocalNodeConnectInfo CardanoMode
NodeQueries.localNodeConnectInfo NetworkId
rnNetworkId String
rnNodeSocket
in forall (m :: * -> *) a.
Tracer m WalletLog -> TracerMonadLogT m a -> m a
runTracerMonadLogT Tracer IO WalletLog
tracer forall a b. (a -> b) -> a -> b
$ do
forall e (m :: * -> *) a.
LocalNodeConnectInfo CardanoMode
-> MonadBlockchainCardanoNodeT e m a
-> m (Either (MonadBlockchainError e) a)
runMonadBlockchainCardanoNodeT @e LocalNodeConnectInfo CardanoMode
info forall (m :: * -> *).
(MonadFail m, MonadLog m, MonadBlockchain m) =>
m a
h forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (forall (m :: * -> *) a. MonadFail m => String -> m a
fail forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> String
show) forall (f :: * -> *) a. Applicative f => a -> f a
pure
balanceAndSubmit :: Tracer IO WalletLog -> RunningNode -> Wallet -> TxBodyContent BuildTx BabbageEra -> IO (Tx BabbageEra)
balanceAndSubmit :: Tracer IO WalletLog
-> RunningNode
-> Wallet
-> TxBodyContent BuildTx BabbageEra
-> IO (Tx BabbageEra)
balanceAndSubmit Tracer IO WalletLog
tracer RunningNode
node Wallet
wallet TxBodyContent BuildTx BabbageEra
tx = do
NetworkId
n <- forall e a.
Show e =>
Tracer IO WalletLog
-> RunningNode
-> (forall (m :: * -> *).
(MonadFail m, MonadLog m, MonadBlockchain m) =>
m a)
-> IO a
runningNodeBlockchain @String Tracer IO WalletLog
tracer RunningNode
node forall (m :: * -> *). MonadBlockchain m => m NetworkId
networkId
let walletAddress :: AddressInEra BabbageEra
walletAddress = forall era.
IsShelleyBasedEra era =>
NetworkId -> Wallet -> AddressInEra era
Wallet.addressInEra NetworkId
n Wallet
wallet
txOut :: TxOut CtxTx BabbageEra
txOut = AddressInEra BabbageEra -> TxOut CtxTx BabbageEra
emptyTxOut AddressInEra BabbageEra
walletAddress
Tracer IO WalletLog
-> RunningNode
-> Wallet
-> TxOut CtxTx BabbageEra
-> TxBodyContent BuildTx BabbageEra
-> IO (Tx BabbageEra)
balanceAndSubmitReturn Tracer IO WalletLog
tracer RunningNode
node Wallet
wallet TxOut CtxTx BabbageEra
txOut TxBodyContent BuildTx BabbageEra
tx
balanceAndSubmitReturn :: Tracer IO WalletLog -> RunningNode -> Wallet -> C.TxOut C.CtxTx C.BabbageEra -> TxBodyContent BuildTx BabbageEra -> IO (Tx BabbageEra)
balanceAndSubmitReturn :: Tracer IO WalletLog
-> RunningNode
-> Wallet
-> TxOut CtxTx BabbageEra
-> TxBodyContent BuildTx BabbageEra
-> IO (Tx BabbageEra)
balanceAndSubmitReturn Tracer IO WalletLog
tracer RunningNode
node Wallet
wallet TxOut CtxTx BabbageEra
returnOutput TxBodyContent BuildTx BabbageEra
tx = do
UtxoSet CtxUTxO ()
utxos <- RunningNode -> Wallet -> IO (UtxoSet CtxUTxO ())
walletUtxos RunningNode
node Wallet
wallet
forall e a.
Show e =>
Tracer IO WalletLog
-> RunningNode
-> (forall (m :: * -> *).
(MonadFail m, MonadLog m, MonadBlockchain m) =>
m a)
-> IO a
runningNodeBlockchain @String Tracer IO WalletLog
tracer RunningNode
node forall a b. (a -> b) -> a -> b
$ do
(Tx BabbageEra
tx', BalanceChanges
_) <- forall (m :: * -> *) a.
(MonadBlockchain m, MonadFail m) =>
Wallet
-> UtxoSet CtxUTxO a
-> TxOut CtxTx BabbageEra
-> TxBodyContent BuildTx BabbageEra
-> m (Tx BabbageEra, BalanceChanges)
CoinSelection.balanceForWalletReturn Wallet
wallet UtxoSet CtxUTxO ()
utxos TxOut CtxTx BabbageEra
returnOutput TxBodyContent BuildTx BabbageEra
tx
TxId
_ <- forall (m :: * -> *). MonadBlockchain m => Tx BabbageEra -> m TxId
sendTx Tx BabbageEra
tx'
forall (f :: * -> *) a. Applicative f => a -> f a
pure Tx BabbageEra
tx'
data WalletLog =
WalletLogInfo Text
| WalletLogWarn Text
| GeneratedWallet Wallet
deriving stock (Int -> WalletLog -> ShowS
[WalletLog] -> ShowS
WalletLog -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [WalletLog] -> ShowS
$cshowList :: [WalletLog] -> ShowS
show :: WalletLog -> String
$cshow :: WalletLog -> String
showsPrec :: Int -> WalletLog -> ShowS
$cshowsPrec :: Int -> WalletLog -> ShowS
Show, forall x. Rep WalletLog x -> WalletLog
forall x. WalletLog -> Rep WalletLog x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep WalletLog x -> WalletLog
$cfrom :: forall x. WalletLog -> Rep WalletLog x
Generic)
deriving anyclass ([WalletLog] -> Encoding
[WalletLog] -> Value
WalletLog -> Encoding
WalletLog -> Value
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [WalletLog] -> Encoding
$ctoEncodingList :: [WalletLog] -> Encoding
toJSONList :: [WalletLog] -> Value
$ctoJSONList :: [WalletLog] -> Value
toEncoding :: WalletLog -> Encoding
$ctoEncoding :: WalletLog -> Encoding
toJSON :: WalletLog -> Value
$ctoJSON :: WalletLog -> Value
ToJSON, Value -> Parser [WalletLog]
Value -> Parser WalletLog
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
parseJSONList :: Value -> Parser [WalletLog]
$cparseJSONList :: Value -> Parser [WalletLog]
parseJSON :: Value -> Parser WalletLog
$cparseJSON :: Value -> Parser WalletLog
FromJSON)
newtype TracerMonadLogT m a = TracerMonadLogT{forall (m :: * -> *) a.
TracerMonadLogT m a -> ReaderT (Tracer m WalletLog) m a
unTracerMonadLogT :: ReaderT (Tracer m WalletLog) m a}
deriving newtype (forall a b. a -> TracerMonadLogT m b -> TracerMonadLogT m a
forall a b. (a -> b) -> TracerMonadLogT m a -> TracerMonadLogT m b
forall (m :: * -> *) a b.
Functor m =>
a -> TracerMonadLogT m b -> TracerMonadLogT m a
forall (m :: * -> *) a b.
Functor m =>
(a -> b) -> TracerMonadLogT m a -> TracerMonadLogT m b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: forall a b. a -> TracerMonadLogT m b -> TracerMonadLogT m a
$c<$ :: forall (m :: * -> *) a b.
Functor m =>
a -> TracerMonadLogT m b -> TracerMonadLogT m a
fmap :: forall a b. (a -> b) -> TracerMonadLogT m a -> TracerMonadLogT m b
$cfmap :: forall (m :: * -> *) a b.
Functor m =>
(a -> b) -> TracerMonadLogT m a -> TracerMonadLogT m b
Functor, forall a. a -> TracerMonadLogT m a
forall a b.
TracerMonadLogT m a -> TracerMonadLogT m b -> TracerMonadLogT m a
forall a b.
TracerMonadLogT m a -> TracerMonadLogT m b -> TracerMonadLogT m b
forall a b.
TracerMonadLogT m (a -> b)
-> TracerMonadLogT m a -> TracerMonadLogT m b
forall a b c.
(a -> b -> c)
-> TracerMonadLogT m a
-> TracerMonadLogT m b
-> TracerMonadLogT m c
forall (f :: * -> *).
Functor f
-> (forall a. a -> f a)
-> (forall a b. f (a -> b) -> f a -> f b)
-> (forall a b c. (a -> b -> c) -> f a -> f b -> f c)
-> (forall a b. f a -> f b -> f b)
-> (forall a b. f a -> f b -> f a)
-> Applicative f
forall {m :: * -> *}. Applicative m => Functor (TracerMonadLogT m)
forall (m :: * -> *) a. Applicative m => a -> TracerMonadLogT m a
forall (m :: * -> *) a b.
Applicative m =>
TracerMonadLogT m a -> TracerMonadLogT m b -> TracerMonadLogT m a
forall (m :: * -> *) a b.
Applicative m =>
TracerMonadLogT m a -> TracerMonadLogT m b -> TracerMonadLogT m b
forall (m :: * -> *) a b.
Applicative m =>
TracerMonadLogT m (a -> b)
-> TracerMonadLogT m a -> TracerMonadLogT m b
forall (m :: * -> *) a b c.
Applicative m =>
(a -> b -> c)
-> TracerMonadLogT m a
-> TracerMonadLogT m b
-> TracerMonadLogT m c
<* :: forall a b.
TracerMonadLogT m a -> TracerMonadLogT m b -> TracerMonadLogT m a
$c<* :: forall (m :: * -> *) a b.
Applicative m =>
TracerMonadLogT m a -> TracerMonadLogT m b -> TracerMonadLogT m a
*> :: forall a b.
TracerMonadLogT m a -> TracerMonadLogT m b -> TracerMonadLogT m b
$c*> :: forall (m :: * -> *) a b.
Applicative m =>
TracerMonadLogT m a -> TracerMonadLogT m b -> TracerMonadLogT m b
liftA2 :: forall a b c.
(a -> b -> c)
-> TracerMonadLogT m a
-> TracerMonadLogT m b
-> TracerMonadLogT m c
$cliftA2 :: forall (m :: * -> *) a b c.
Applicative m =>
(a -> b -> c)
-> TracerMonadLogT m a
-> TracerMonadLogT m b
-> TracerMonadLogT m c
<*> :: forall a b.
TracerMonadLogT m (a -> b)
-> TracerMonadLogT m a -> TracerMonadLogT m b
$c<*> :: forall (m :: * -> *) a b.
Applicative m =>
TracerMonadLogT m (a -> b)
-> TracerMonadLogT m a -> TracerMonadLogT m b
pure :: forall a. a -> TracerMonadLogT m a
$cpure :: forall (m :: * -> *) a. Applicative m => a -> TracerMonadLogT m a
Applicative, forall a. a -> TracerMonadLogT m a
forall a b.
TracerMonadLogT m a -> TracerMonadLogT m b -> TracerMonadLogT m b
forall a b.
TracerMonadLogT m a
-> (a -> TracerMonadLogT m b) -> TracerMonadLogT m b
forall {m :: * -> *}. Monad m => Applicative (TracerMonadLogT m)
forall (m :: * -> *) a. Monad m => a -> TracerMonadLogT m a
forall (m :: * -> *) a b.
Monad m =>
TracerMonadLogT m a -> TracerMonadLogT m b -> TracerMonadLogT m b
forall (m :: * -> *) a b.
Monad m =>
TracerMonadLogT m a
-> (a -> TracerMonadLogT m b) -> TracerMonadLogT m b
forall (m :: * -> *).
Applicative m
-> (forall a b. m a -> (a -> m b) -> m b)
-> (forall a b. m a -> m b -> m b)
-> (forall a. a -> m a)
-> Monad m
return :: forall a. a -> TracerMonadLogT m a
$creturn :: forall (m :: * -> *) a. Monad m => a -> TracerMonadLogT m a
>> :: forall a b.
TracerMonadLogT m a -> TracerMonadLogT m b -> TracerMonadLogT m b
$c>> :: forall (m :: * -> *) a b.
Monad m =>
TracerMonadLogT m a -> TracerMonadLogT m b -> TracerMonadLogT m b
>>= :: forall a b.
TracerMonadLogT m a
-> (a -> TracerMonadLogT m b) -> TracerMonadLogT m b
$c>>= :: forall (m :: * -> *) a b.
Monad m =>
TracerMonadLogT m a
-> (a -> TracerMonadLogT m b) -> TracerMonadLogT m b
Monad, forall a. String -> TracerMonadLogT m a
forall (m :: * -> *).
Monad m -> (forall a. String -> m a) -> MonadFail m
forall {m :: * -> *}. MonadFail m => Monad (TracerMonadLogT m)
forall (m :: * -> *) a.
MonadFail m =>
String -> TracerMonadLogT m a
fail :: forall a. String -> TracerMonadLogT m a
$cfail :: forall (m :: * -> *) a.
MonadFail m =>
String -> TracerMonadLogT m a
MonadFail, forall a. IO a -> TracerMonadLogT m a
forall (m :: * -> *).
Monad m -> (forall a. IO a -> m a) -> MonadIO m
forall {m :: * -> *}. MonadIO m => Monad (TracerMonadLogT m)
forall (m :: * -> *) a. MonadIO m => IO a -> TracerMonadLogT m a
liftIO :: forall a. IO a -> TracerMonadLogT m a
$cliftIO :: forall (m :: * -> *) a. MonadIO m => IO a -> TracerMonadLogT m a
MonadIO)
runTracerMonadLogT :: Tracer m WalletLog -> TracerMonadLogT m a -> m a
runTracerMonadLogT :: forall (m :: * -> *) a.
Tracer m WalletLog -> TracerMonadLogT m a -> m a
runTracerMonadLogT Tracer m WalletLog
t (TracerMonadLogT ReaderT (Tracer m WalletLog) m a
r) = forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT ReaderT (Tracer m WalletLog) m a
r Tracer m WalletLog
t
instance Monad m => MonadLog (TracerMonadLogT m) where
logInfo' :: Doc Void -> TracerMonadLogT m ()
logInfo' Doc Void
msg = forall (m :: * -> *) a.
ReaderT (Tracer m WalletLog) m a -> TracerMonadLogT m a
TracerMonadLogT forall a b. (a -> b) -> a -> b
$ do
Tracer m WalletLog
tr <- forall r (m :: * -> *). MonadReader r m => m r
ask
let rendered :: Text
rendered = forall ann. SimpleDocStream ann -> Text
Render.renderStrict (forall ann. LayoutOptions -> Doc ann -> SimpleDocStream ann
layoutPretty LayoutOptions
defaultLayoutOptions Doc Void
msg)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (forall (m :: * -> *) a. Tracer m a -> a -> m ()
traceWith Tracer m WalletLog
tr (Text -> WalletLog
WalletLogInfo Text
rendered))
logWarn' :: Doc Void -> TracerMonadLogT m ()
logWarn' Doc Void
msg = forall (m :: * -> *) a.
ReaderT (Tracer m WalletLog) m a -> TracerMonadLogT m a
TracerMonadLogT forall a b. (a -> b) -> a -> b
$ do
Tracer m WalletLog
tr <- forall r (m :: * -> *). MonadReader r m => m r
ask
let rendered :: Text
rendered = forall ann. SimpleDocStream ann -> Text
Render.renderStrict (forall ann. LayoutOptions -> Doc ann -> SimpleDocStream ann
layoutPretty LayoutOptions
defaultLayoutOptions Doc Void
msg)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (forall (m :: * -> *) a. Tracer m a -> a -> m ()
traceWith Tracer m WalletLog
tr (Text -> WalletLog
WalletLogWarn Text
rendered))
logDebug' :: Doc Void -> TracerMonadLogT m ()
logDebug' Doc Void
msg = forall (m :: * -> *) a.
ReaderT (Tracer m WalletLog) m a -> TracerMonadLogT m a
TracerMonadLogT forall a b. (a -> b) -> a -> b
$ do
Tracer m WalletLog
tr <- forall r (m :: * -> *). MonadReader r m => m r
ask
let rendered :: Text
rendered = forall ann. SimpleDocStream ann -> Text
Render.renderStrict (forall ann. LayoutOptions -> Doc ann -> SimpleDocStream ann
layoutPretty LayoutOptions
defaultLayoutOptions Doc Void
msg)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (forall (m :: * -> *) a. Tracer m a -> a -> m ()
traceWith Tracer m WalletLog
tr (Text -> WalletLog
WalletLogWarn Text
rendered))