type systems : more than int ≠ bool
compiler-assistance : e.g. metaprogramming
PureScript
Haskell
FOAM
Core Contrib
Oct
Nov
2017
2018
Mar
May
1
2
3
4
Dec
Apr
5
...
Examples of Effects
Examples of Pure Functions
import Data.ByteString as BS
import Network.Ethereum.Core.HexString
-- | Opaque PrivateKey type
newtype PrivateKey = PrivateKey BS.ByteString
-- | Opaque PublicKey type
newtype PublicKey = PublicKey BS.ByteString
-- | Represents and Ethereum address, which is a 20 byte `HexString`
newtype Address = Address HexString
Excerpts from Network.Ethereum.Core.Signatures
unPublicKey :: PublicKey -> HexString
mkPublicKey :: HexString -> Maybe PublicKey
unPrivateKey :: PrivateKey -> HexString
mkPrivateKey :: HexString -> Maybe PrivateKey
-- | Produce the `PublicKey` for the corresponding `PrivateKey`.
foreign import privateToPublic :: PrivateKey -> PublicKey
unAddress :: Address -> HexString
mkAddress :: HexString -> Maybe Address
-- | Produce the `Address` corresponding to the `PrivateKey`.
privateToAddress :: PrivateKey -> Address
-- | Produce the `Address` corresponding to the `PublicKey`
publicToAddress :: PublicKey -> Address
class ABIEncode a where
toDataBuilder :: a -> HexString
-- | type Parser String a = ExceptT ParseError (State (ParseState HexString)) a
class ABIDecode a where
fromDataParser :: Parser HexString a
-- | Parse encoded value, droping the leading `0x`
fromData :: forall a . ABIDecode a => HexString -> Either ParseError a
fromData s = runParser s fromDataParser
instance abiDecodeAddress :: ABIDecode Address where
fromDataParser = do
_ <- take 24
addressBytes <- take 40
case mkAddress addressBytes of
Nothing -> fail "Address is 20 bytes, receieved more"
Just addr -> addr
instance abiDecodeVector
:: ( ABIDecode a
, KnownSize n
)
=> ABIDecode (Vector n a) where
fromDataParser =
let len = sizeVal (DLProxy :: DLProxy n)
in replicateA len fromDataParser
myAddresses = Either ParseError (Vector (DLProxy D2) Address)
myAddresses =
fromData "0x0000000000000000000000000000000000000000000000000000000000000002
0000000000000000000000003a9bCa3065b263046CEf072210cdb5845B05f1A3
0000000000000000000000001eA6e6eCDe9A6B8229Ebf73e391b16dd63fc038B"
secondAddress :: Either String Address
secondAddress = case myAddresses of
-- in case of error print a nice message
Left parseError -> Left ("Error parsing myAddresses: " <> show parseError)
-- in case of success, grab the address at index 1, guaranteed to succeed.
Right addresses -> addresses !! (DProxy :: DProxy D1)
How this might be useful
-- Web3 is a context that has access to a web3 provider and
-- can make aysynchronous computations. It can also throw
-- excptions via Aff.
newtype Web3 a = Web3 (ReaderT Provider Aff a)
...
-- | Call a function on a particular block's state root.
eth_call :: TransactionOptions NoPay -> ChainCursor -> Web3 HexString
...
Taken from Web3Spec.Live.MockERC20Spec
...
let
{contractAddress: mockERC20Address, userAddress} = cfg
-- number of tokens to transfer
amount = mkUIntN s256 1
recipient = nullAddress
-- set the `to` and `from fields for the transaction options
txOptions = defaultTestTxOptions # _from ?~ userAddress
# _to ?~ mockERC20Address
transferAction :: Web3 HexString
transferAction = MockERC20.transfer txOptions {to : recipient, amount : amount}
-- await for a `Transfer` event emitted from contract with address
-- `mockERC20Address` after running `transferAction`
Tuple _ (MockERC20.Transfer tfr) <- assertWeb3 provider $
takeEvent (Proxy :: Proxy MockERC20.Transfer) mockERC20Address transferAction
-- check that the transfer amount is the amount sent.
tfr.amount `shouldEqual` amount
...
Martin Allen, Charles Crain, Irakli Safareli
Day 2, Wednesday, 11.30am - 2.30pm A2