Smart contracts

If Ethereum is a World Computer then smart contract is a program for that. hs-web3 provide functions and abstractions to compile, deploy and interact with smart contracts.

Note

Currently Solidity is de facto standard for Ethereum smart contract development. Please read intro to get more knowledge about Solidity smart contracts.

Contract ABI

One of the most important thing that Solidity introduce is a contract Application Binary Interface. ABI is a standard for smart contract communication, both from outside the Ethereum and for contract-to-contract interaction. In hs-web3 Quasiquotation is used to parse contract JSON ABI or load from file. TemplateHaskell driven generator creates ABI encoding instances and contract method helpers automatically.

{-# LANGUAGE DataKinds             #-}
{-# LANGUAGE DeriveGeneric         #-}
{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings     #-}
{-# LANGUAGE QuasiQuotes           #-}
module ERC20 where

import           Network.Ethereum.Contract.TH

[abiFrom|ERC20.json|]

Using Solidity contract ABI generator creates helper functions like a transfer and balanceOf.

transfer :: (JsonRpc m, Account a t, Functor (t m)) => Address -> UIntN 256 -> t m TxReceipt

balanceOf :: (JsonRpc m, Account a t, Functor (t m)) => Address -> t m (UIntN 256)

Note

Use -ddump-splices to see generated code during compilation or in GHCi.

Helper functions wraps building and sending transaction with given argument and function selector. This behaviour is very similar to web3.js contract object.

ABI encoding

To build transaction input from Solidity method call special encoding is used. hs-web3 implements Solidity ABI encoding for primitive and composed types. Codecs are placed at Data.Solidity.Abi.Codec.

encode :: (AbiPut a, ByteArray ba) => a -> ba

decode :: (ByteArrayAccess ba, AbiGet a) => ba -> Either String a

Note

When I develop codecs I was inspired by cereal library. As result AbiGet and AbiPut classes are analogue to cereal Serialize.

Primitive solidity types are placed at Data.Solidity.Prim, this module exports types like an Address or UIntN.

> import Data.Solidity.Prim
> import Data.Solidity.Abi.Codec
> encode (42 :: UIntN 128) :: HexString
HexString "0x000000000000000000000000000000000000000000000000000000000000002a"
> encode (42 :: IntN 256, "Hello" :: Text) :: HexString
HexString "0x000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000"

Contract deployment

To deploy smart contract special function with name new is used.

-- | Create new smart contract on blockchain
new :: (Account p t, JsonRpc m, Method a, Monad (t m))
    => a
    -- ^ Contract constructor
    -> t m (Maybe Address)
    -- ^ Address of deployed contract when transaction success

This function use Method instance of contract constructor (*Contract data type) to encode transaction input and send it without destination to create new contract.

Just address <- runWeb3 $ withAccount () $ withParam id $ new SimpleStorageContract