{-# LANGUAGE FlexibleContexts #-}

-- |
-- Module      :  Network.Ethereum.Account.Safe
-- Copyright   :  Alexander Krupenkin 2018
-- License     :  BSD3
--
-- Maintainer  :  mail@akru.me
-- Stability   :  experimental
-- Portability :  unportable
--
-- Safe sending of Ethereum transaction.
--

module Network.Ethereum.Account.Safe where

import           Control.Concurrent                (threadDelay)
import           Control.Monad.IO.Class            (liftIO)
import           Control.Monad.Trans               (lift)

import           Network.Ethereum.Account.Class    (Account (send))
import           Network.Ethereum.Account.Internal (updateReceipt)
import qualified Network.Ethereum.Api.Eth          as Eth
import           Network.Ethereum.Api.Types        (TxReceipt (receiptBlockNumber))
import           Network.Ethereum.Contract.Method  (Method)
import           Network.JsonRpc.TinyClient        (JsonRpc)

-- | Safe version of 'send' function of 'Account' typeclass
-- Waiting for some blocks of transaction confirmation before return
safeSend :: (Account p t, JsonRpc m, Method args, Monad (t m))
         => Integer
         -- ^ Confirmation in blocks
         -> args
         -- ^ Contract method arguments
         -> t m TxReceipt
         -- ^ Receipt of sended transaction
safeSend b a = lift . waiting =<< send a
  where
    waiting receipt =
        case receiptBlockNumber receipt of
            Nothing -> do
                liftIO $ threadDelay 1000000
                waiting =<< updateReceipt receipt
            Just bn -> do
                current <- Eth.blockNumber
                if current - bn >= fromInteger b
                    then return receipt
                    else do liftIO $ threadDelay 1000000
                            waiting receipt

-- | Count block confirmation to keep secure
-- According to Vitalik post
-- https://blog.ethereum.org/2015/09/14/on-slow-and-fast-block-times/
safeConfirmations :: Integer
safeConfirmations = 10