Ethereum accounts

Note

Ethereum whitepaper mention two types of accounts: smart contract and external owned account (EOA). But EOA only can send transaction to network. In this page EOA managing and generalized transaction sending is described.

hs-web3 support a few kinds of EOA described in table below.

Type Description
Default typically first of node accounts list, should be unlocked
Personal available via personal_* JSON-RPC, password required
PrivateKey derived from secp256k1 private key, use JSON-RPC sendRawTransaction

All of them has an instance for Account typeclass.

class MonadTrans t => Account a t | t -> a where
   -- | Run computation with given account credentials
   withAccount :: JsonRpc m => a -> t m b -> m b

   -- | Send transaction to contract, like a 'write' command
   send :: (JsonRpc m, Method args) => args -> t m TxReceipt

   -- | Call constant method of contract, like a 'read' command
   call :: (JsonRpc m, Method args, AbiGet result) => args -> t m result

The Account is a multi-parameter typeclass that define most important EOA actions.

Account managing

The first parameter of Account typeclass is an account internal params presended as independent data type.

-- | Unlockable node managed account params
data Personal = Personal
   { personalAddress    :: !Address
   , personalPassphrase :: !Passphrase
   } deriving (Eq, Show)

In this example Personal data contains of two params: personal account address and password. For using account credentials Account typeclass provide special function withAccount.

-- | Run computation with given account credentials
withAccount :: JsonRpc m => a -> t m b -> m b

withAccount function takes two arguments: account initialization parameters (some credentials like a password or private key) and computation to run it in given account context. Finally it returns JsonRpc computation that can be runned using any web3 provider.

runWeb3 $ do

   -- Run with default account context
   withAccount () $ ...

   -- Run with personal account context
   withAccount (Personal "0x..." "password") $ ...

Transaction sending

The second parameter of Account typeclass is transaction parametrization monad. This monad do one thing - prepare transaction parameters before call.

Note

Transaction sending diagram by layer looks like provider -> account -> transaction, provider at low level, account at middle layer and transaction former at high level.

withParam is a special function, it behaviour is very similar to withStateT function. It used to set parameters of transaction locally and revert params after out of scope.

withParam :: Account p (AccountT p)
          => (CallParam p -> CallParam p)
          -> AccountT p m a
          -> AccountT p m a

The first argument of withParam function is state transition function, second - the computation to run in context of changed state. CallParam helps to parametrize transaction sending, lenses is very useful for this purpose.

runWeb3 $
   withAccount () $
      withParam (to .~ alice) $
         ...

Where lens to is used for setting transaction recipient address. All transaction parametrization lenses presended in table below.

Note

By default transaction gas limit estimated according to transaction input but it also can be set manually.

Finally for sending transactions Account typeclass provide two functions:

-- | Send transaction to contract, like a 'write' command
send :: (JsonRpc m, Method args) => args -> t m TxReceipt

-- | Call constant method of contract, like a 'read' command
call :: (JsonRpc m, Method args, AbiGet result) => args -> t m result

Note

Functions above can be run in account context only and transaction parameters should be set before.

Safe transactions

Default behaviour of send function is send transaction and waiting for transaction receipt. It does mean that transaction is already in blockchain when execution flow get back. But finalization in Ethereum is probabilistic. For this reason waiting for some count of confirmation is a good practics for safe transaction sending.

Note

Vitalik Buterin blog post describe how much confirmation is required for high probability of transaction finality. For using this value import safeConfirmations from Network.Ethereum.Account.Safe module.

Module Network.Ethereum.Account.Safe implements function safeSend. It very similar to send but take count of transaction confirmation as first argument.

send = safeSend 0