web3 0.7.3.0 → 0.8.0.0
raw patch · 107 files changed
+14193/−3344 lines, 107 filesdep +OneTupledep +containersdep +microlensdep ~aesondep ~basedep ~basement
Dependencies added: OneTuple, containers, microlens, microlens-aeson, microlens-mtl, microlens-th, random, relapse, secp256k1-haskell, vinyl
Dependency ranges changed: aeson, base, basement, bytestring, cereal, cryptonite, generics-sop, hspec, hspec-discover, http-client, http-client-tls, memory, mtl, parsec, split, stm, template-haskell, text, time
Files
- CHANGELOG.md +27/−0
- LICENSE +1/−1
- README.md +55/−52
- cbits/solidity_lite.cpp +99/−0
- examples/ERC20.hs +0/−11
- examples/ERC20.json +0/−1
- examples/TokenInfo.hs +0/−29
- examples/token/ERC20.hs +12/−0
- examples/token/ERC20.json +1/−0
- examples/token/Main.hs +27/−0
- src/Crypto/Ethereum.hs +59/−0
- src/Data/ByteArray/HexString.hs +71/−0
- src/Data/Solidity/Abi.hs +68/−0
- src/Data/Solidity/Abi/Codec.hs +66/−0
- src/Data/Solidity/Abi/Generic.hs +123/−0
- src/Data/Solidity/Event.hs +142/−0
- src/Data/Solidity/Event/Internal.hs +136/−0
- src/Data/Solidity/Prim.hs +30/−0
- src/Data/Solidity/Prim/Address.hs +123/−0
- src/Data/Solidity/Prim/Bool.hs +25/−0
- src/Data/Solidity/Prim/Bytes.hs +126/−0
- src/Data/Solidity/Prim/Int.hs +139/−0
- src/Data/Solidity/Prim/List.hs +56/−0
- src/Data/Solidity/Prim/String.hs +29/−0
- src/Data/Solidity/Prim/Tagged.hs +37/−0
- src/Data/Solidity/Prim/Tuple.hs +38/−0
- src/Data/Solidity/Prim/Tuple/TH.hs +34/−0
- src/Data/String/Extra.hs +1/−1
- src/Language/Solidity/Abi.hs +284/−0
- src/Language/Solidity/Compiler.hs +58/−0
- src/Language/Solidity/Compiler/Foreign.hsc +106/−0
- src/Network/Ethereum/ABI/Class.hs +0/−71
- src/Network/Ethereum/ABI/Codec.hs +0/−63
- src/Network/Ethereum/ABI/Event.hs +0/−144
- src/Network/Ethereum/ABI/Event/Internal.hs +0/−136
- src/Network/Ethereum/ABI/Generic.hs +0/−126
- src/Network/Ethereum/ABI/Json.hs +0/−280
- src/Network/Ethereum/ABI/Prim.hs +0/−30
- src/Network/Ethereum/ABI/Prim/Address.hs +0/−81
- src/Network/Ethereum/ABI/Prim/Bool.hs +0/−29
- src/Network/Ethereum/ABI/Prim/Bytes.hs +0/−118
- src/Network/Ethereum/ABI/Prim/Int.hs +0/−119
- src/Network/Ethereum/ABI/Prim/List.hs +0/−55
- src/Network/Ethereum/ABI/Prim/String.hs +0/−29
- src/Network/Ethereum/ABI/Prim/Tagged.hs +0/−36
- src/Network/Ethereum/ABI/Prim/Tuple.hs +0/−45
- src/Network/Ethereum/ABI/Prim/Tuple/TH.hs +0/−34
- src/Network/Ethereum/Account.hs +54/−0
- src/Network/Ethereum/Account/Class.hs +56/−0
- src/Network/Ethereum/Account/Default.hs +72/−0
- src/Network/Ethereum/Account/Internal.hs +130/−0
- src/Network/Ethereum/Account/Personal.hs +81/−0
- src/Network/Ethereum/Account/PrivateKey.hs +127/−0
- src/Network/Ethereum/Account/Safe.hs +55/−0
- src/Network/Ethereum/Api/Eth.hs +248/−0
- src/Network/Ethereum/Api/Net.hs +35/−0
- src/Network/Ethereum/Api/Personal.hs +93/−0
- src/Network/Ethereum/Api/Provider.hs +87/−0
- src/Network/Ethereum/Api/Types.hs +298/−0
- src/Network/Ethereum/Api/Web3.hs +30/−0
- src/Network/Ethereum/Chain.hs +36/−0
- src/Network/Ethereum/Contract.hs +49/−0
- src/Network/Ethereum/Contract/Event.hs +10/−185
- src/Network/Ethereum/Contract/Event/Common.hs +86/−0
- src/Network/Ethereum/Contract/Event/MultiFilter.hs +457/−0
- src/Network/Ethereum/Contract/Event/SingleFilter.hs +256/−0
- src/Network/Ethereum/Contract/Method.hs +15/−53
- src/Network/Ethereum/Contract/TH.hs +128/−70
- src/Network/Ethereum/Ens.hs +61/−0
- src/Network/Ethereum/Ens/PublicResolver.hs +25/−0
- src/Network/Ethereum/Ens/Registry.hs +25/−0
- src/Network/Ethereum/Unit.hs +20/−20
- src/Network/Ethereum/Web3.hs +20/−25
- src/Network/Ethereum/Web3/Eth.hs +0/−250
- src/Network/Ethereum/Web3/Net.hs +0/−35
- src/Network/Ethereum/Web3/Provider.hs +0/−94
- src/Network/Ethereum/Web3/Types.hs +0/−315
- src/Network/Ethereum/Web3/Web3.hs +0/−31
- src/Network/JsonRpc/TinyClient.hs +125/−87
- stack.yaml +27/−0
- test-support/contracts/Migrations.sol +0/−23
- test-support/contracts/SimpleStorage.sol +0/−12
- test-support/convertAbi.sh +0/−9
- test-support/inject-contract-addresses.sh +0/−26
- test-support/migrations/1_initial_migration.js +0/−5
- test-support/migrations/2_deploy_contracts.js +0/−7
- test-support/truffle.js +0/−9
- test/Network/Ethereum/Web3/Test/ComplexStorageSpec.hs +72/−51
- test/Network/Ethereum/Web3/Test/ERC20Spec.hs +24/−0
- test/Network/Ethereum/Web3/Test/LinearizationSpec.hs +192/−0
- test/Network/Ethereum/Web3/Test/RegistrySpec.hs +32/−0
- test/Network/Ethereum/Web3/Test/SimpleStorageSpec.hs +112/−127
- test/Network/Ethereum/Web3/Test/Utils.hs +55/−76
- test/contracts/ComplexStorage.json +4533/−0
- test/contracts/Linearization.json +2716/−0
- test/contracts/Registry.json +506/−0
- test/contracts/SimpleStorage.json +600/−0
- unit/Crypto/Ethereum/Test/EcdsaSpec.hs +32/−0
- unit/Data/Solidity/Test/AddressSpec.hs +62/−0
- unit/Data/Solidity/Test/EncodingSpec.hs +265/−0
- unit/Data/Solidity/Test/IntSpec.hs +33/−0
- unit/Language/Solidity/Test/CompilerSpec.hs +21/−0
- unit/Network/Ethereum/Web3/Test/EncodingSpec.hs +0/−224
- unit/Network/Ethereum/Web3/Test/EventSpec.hs +21/−13
- unit/Network/Ethereum/Web3/Test/LocalAccountSpec.hs +26/−0
- unit/Network/Ethereum/Web3/Test/MethodDumpSpec.hs +1/−2
- web3.cabal +211/−104
CHANGELOG.md view
@@ -1,6 +1,33 @@ # Changelog All notable changes to this project will be documented in this file. +## [0.8.0.0] 2018-10-**+### Added+- Support for Ethereum cryptography+- Local private key transaction signer +- Generalized JSON-RPC monad for API methods+- Support for multiple transaction sending methods via one `Account` api+- Monad based transaction sending parametrization +- Experimental support for solidity compiler (disabled by default) +- Support for Ethereum mainnet ENS resolver+- Contract typeclass with api/bytecode getters+- Contract typeclass TH generator+- Function for creating contracts+- Event single/multi filters+- HexString data type+- Personal api calls+- Address checksum++### Changed+- package.yaml instead web3.cabal package descriptor+- Solidity related data types and codecs moved to Data.Solidity+- Solidity related parsers and compiler moved to Language.Solidity+- Modules in Network.Ethereum.Web3 moved to Network.Ethereum.Api+- fromWei/toWei from `Unit` typeclass now operates over `Integral`++### Removed+- `convert` function from `Unit` typeclass+ ## [0.7.3.0] 2018-05-22 ### Added - 'Network.Ethereum.ABI.Prim' meta-module as primitive types and instances aggregator.
LICENSE view
@@ -1,4 +1,4 @@-Copyright Alexander Krupenkin (c) 2016+Copyright Alexander Krupenkin (c) 2016-2018 All rights reserved.
README.md view
@@ -1,76 +1,79 @@-## Ethereum Haskell API+Ethereum API for Haskell+======================== -This is the Ethereum compatible Haskell API which implements the [Generic JSON RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC) spec.+The Haskell Ethereum API which implements the [Generic JSON RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC). +[](https://hs-web3.readthedocs.io/en/latest/?badge=latest) [](https://travis-ci.org/airalab/hs-web3)-[](https://ci.appveyor.com/project/akru/hs-web3) [](http://hackage.haskell.org/package/web3)-+[](http://stackage.org/lts-12/package/web3)+[](http://stackage.org/nightly/package/web3)+[](https://www.codetriage.com/airalab/hs-web3) -[](https://www.codetriage.com/airalab/hs-web3) -### Installation+Install+------- - $ git clone https://github.com/airalab/hs-web3 && cd hs-web3- $ stack setup- $ stack ghci+`stack install web3` -> This library runs only paired with [geth](https://github.com/ethereum/go-ethereum)-> or [parity](https://github.com/ethcore/parity) Ethereum node,-> please start node first before using the library.+Usage+----- -### Web3 monad+```haskell+{-# LANGUAGE OverloadedStrings #-}+module Main where -Any Ethereum node communication wrapped with `Web3` monadic type.+-- Basic imports+import Network.Ethereum.Web3 - > import Network.Ethereum.Web3.Web3- > :t clientVersion- clientVersion :: Web3 Text+-- Eth API support+import qualified Network.Ethereum.Api.Eth as Eth+import Network.Ethereum.Api.Types -To run this computation used `runWeb3'` or `runWeb3` functions.+-- ENS support+import qualified Network.Ethereum.Ens as Ens - > import Network.Ethereum.Web3- > runWeb3 clientVersion- Right "Parity//v1.4.5-beta-a028d04-20161126/x86_64-linux-gnu/rustc1.13.0"+-- Lens to simple param setting+import Lens.Micro ((.~)) -Function `runWeb3` use default `Web3` provider at `localhost:8545`.+main :: IO ()+main = do+ -- Use default provider on http://localhost:8545+ ret <- runWeb3 $ do - > :t runWeb3- runWeb3- :: MonadIO m => Web3 a -> m (Either Web3Error a)+ -- Get address of default account+ me <- head <$> Eth.accounts -### TemplateHaskell generator+ -- Get balance of default account on latest block+ myBalance <- Eth.getBalance me Latest -[Quasiquotation](https://wiki.haskell.org/Quasiquotation) is used to parse contract ABI or load from JSON file. [TemplateHaskell](https://wiki.haskell.org/Template_Haskell) driven Haskell contract API generator can automatical create ABI encoding instances and contract method helpers.+ -- Get half of balance+ let halfBalance = fromWei (myBalance / 2) - > :set -XQuasiQuotes- > import Network.Ethereum.Contract.TH- > putStr [abiFrom|data/sample.json|]- Contract:- Events:- Action1(address,uint256)- Action2(string,uint256)- Methods:- 0x03de48b3 runA1()- 0x90126c7a runA2(string,uint256)+ -- Use default account+ withAccount () $ do+ -- Get Ethereum address via ENS+ alice <- Ens.resolve "alice.address.on.eth"+ bob <- Ens.resolve "bob.address.on.eth" -Use `-ddump-splices` to see generated code during compilation or in GHCi. See `examples` folder for more use cases.+ -- Send transaction with value+ withParam (value .~ halfBalance) $ do -### Testing+ -- Send transaction to alice account+ withParam (to .~ alice) $ send () -Testing the `web3` is split up into two suites: `unit` and `live`.-The `unit` suite tests internal library facilities, while the `live` tests that-the library adequately interacts with a Web3 provider.+ -- Send transaction to bob account+ withParam (to .~ bob) $ send () -One may simply run `stack test` to run both suites, or `stack test web3:unit` or `stack test web3:live`-to run the test suites individually.+ -- Return sended value+ return halfBalance -The `unit` suite has no external dependencies, while the `live` suite requires Truffle and `jq`-to be available on your machine.+ -- Web3 error handling+ case ret of+ Left e -> error $ show e+ Right v -> print (v :: Ether) -- Print returned value in ethers+``` -The `live` suite also requires a Web3 provider with Ethereum capabilities, as well as-an unlocked account with ether to send transactions from. It uses Truffle to deploy testing contracts,-generating ABIs for them in the process, then using said ABIs as part of a TemplateHaskell step in the suite.-It is assumed that the provider is available at `http://localhost:8545`. If that's not the case, you must update `truffle.js`-so that Truffle can deploy the contracts correctly, and pass the `WEB3_PROVIDER=http://host:port` environment variable-when running the tests so that the `web3` library can interact with the chain that's being tested against.+---++Read more in the [documentation on ReadTheDocs](https://hs-web3.readthedocs.io).
+ cbits/solidity_lite.cpp view
@@ -0,0 +1,99 @@+#include <solidity_lite.h>+#include <libsolidity/interface/CompilerStack.h>+#include <libsolidity/interface/SourceReferenceFormatter.h>++using namespace dev::solidity;+using namespace std;++struct Solidity {+ Solidity() : compiler(new CompilerStack)+ {}++ ~Solidity()+ { delete compiler; }++ CompilerStack * compiler;+ map<string, dev::h160> libs;+};++#ifdef __cplusplus+extern "C"+{+#endif++namespace dev {+namespace solidity {+namespace lite {++void * create()+{+ return static_cast<void *>(new Solidity);+}++void destroy(void * self)+{+ delete static_cast<Solidity *>(self);+}++int addSource(void * self, const char * name, const char * source)+{+ return static_cast<Solidity*>(self)->compiler->addSource(name, source);+}++int addLibrary(void * self, const char * name, const char * address)+{+ static_cast<Solidity*>(self)->libs[name] = dev::h160(address);+ return 0;+}++int compile(void * self, int optimize)+{+ auto s = static_cast<Solidity *>(self);++ s->compiler->setOptimiserSettings(optimize);+ s->compiler->setLibraries(s->libs);+ s->compiler->reset(true);+ if (s->compiler->parseAndAnalyze()) + if (s->compiler->compile())+ return 0;++ return -1;+}++char * c_string(const std::string &str)+{+ auto c_str = (char *) calloc(1, str.size()+1);+ memcpy(c_str, str.c_str(), str.size());+ return c_str;+}++char * abi(void * self, const char * name)+{+ auto abi_value = static_cast<Solidity *>(self)->compiler->contractABI(name);+ return c_string(abi_value.toStyledString());+}++char * binary(void * self, const char * name)+{+ auto bin_object = static_cast<Solidity *>(self)->compiler->object(name);+ return c_string(bin_object.toHex());+}++char * errors(void * self)+{+ auto compiler = static_cast<Solidity *>(self)->compiler;+ stringstream error_stream;+ for (auto const& error: compiler->errors()) {+ SourceReferenceFormatter fmt(error_stream, [&](string const& _source) -> Scanner const& { return compiler->scanner(_source); });+ fmt.printExceptionInformation(*error, (error->type() == Error::Type::Warning) ? "Warning" : "Error");+ }+ return c_string(error_stream.str());+}++} // solidity+} // lite+} // dev++#ifdef __cplusplus+}+#endif
− examples/ERC20.hs
@@ -1,11 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE QuasiQuotes #-}-module ERC20 where--import Network.Ethereum.Contract.TH--[abiFrom|examples/ERC20.json|]
− examples/ERC20.json
@@ -1,1 +0,0 @@-[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"kill","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"delegate","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"}],"name":"unapprove","outputs":[],"payable":false,"type":"function"},{"inputs":[{"name":"_name","type":"string"},{"name":"_symbol","type":"string"},{"name":"_decimals","type":"uint8"},{"name":"_count","type":"uint256"}],"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Approval","type":"event"}]
− examples/TokenInfo.hs
@@ -1,29 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-module Main where--import Data.Default (def)-import Data.Text (unpack)-import Text.Printf (printf)--import Network.Ethereum.Contract.TH-import Network.Ethereum.Web3 hiding (name)--import ERC20--main :: IO ()-main = do- result <- runWeb3 $ do- n <- name tokenCall- s <- symbol tokenCall- d <- decimals tokenCall- return $ printf "Token %s with symbol %s and decimals %d"- (unpack n) (unpack s) (fromIntegral d :: Int)- case result of- Left err -> print err- Right info -> putStrLn info- where- token :: Address- token = "0xA2f4FCb0FDe2dD59f7a1873e121bc5623e3164Eb"-- tokenCall :: Call- tokenCall = def { callTo = Just token }
+ examples/token/ERC20.hs view
@@ -0,0 +1,12 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+module ERC20 where++import Network.Ethereum.Contract.TH++[abiFrom|examples/ERC20.json|]
+ examples/token/ERC20.json view
@@ -0,0 +1,1 @@+[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"kill","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"delegate","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"}],"name":"unapprove","outputs":[],"payable":false,"type":"function"},{"inputs":[{"name":"_name","type":"string"},{"name":"_symbol","type":"string"},{"name":"_decimals","type":"uint8"},{"name":"_count","type":"uint256"}],"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Approval","type":"event"}]
+ examples/token/Main.hs view
@@ -0,0 +1,27 @@+{-# LANGUAGE OverloadedStrings #-}+module Main where++import Data.Default (def)+import Data.Text (unpack)+import Text.Printf (printf)++import Network.Ethereum.Account+import Network.Ethereum.Web3 hiding (name)++import ERC20++main :: IO ()+main = do+ result <- runWeb3 $+ withAccount () $+ airaToken $ do+ n <- name+ s <- symbol+ d <- decimals+ return $ printf "Token %s with symbol %s and decimals %d"+ (unpack n) (unpack s) (fromIntegral d :: Int)+ case result of+ Left err -> error err+ Right info -> putStrLn info+ where+ airaToken = withParam $ to .~ "0xA2f4FCb0FDe2dD59f7a1873e121bc5623e3164Eb"
+ src/Crypto/Ethereum.hs view
@@ -0,0 +1,59 @@+-- |+-- Module : Crypto.Ethereum+-- Copyright : Alexander Krupenkin 2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : unportable+--+-- Ethereum ECDSA based on secp256k1 bindings.+--++module Crypto.Ethereum+ (+ -- * Ethereum ECDSA sign/recover+ hashMessage+ , ecsign+ , ecrecover++ -- * Re-export useful Secp256k1 functions+ , SecKey+ , derivePubKey+ )where++import Crypto.Hash (Keccak_256 (..), hashWith)+import Crypto.Secp256k1 (CompactRecSig, Msg, SecKey,+ derivePubKey, exportCompactRecSig,+ importCompactRecSig, msg, recover,+ signRecMsg)+import Data.ByteArray (ByteArrayAccess, convert)+import Data.Maybe (fromJust)++import Data.Solidity.Prim.Address (Address, fromPubKey)++-- | SHA3 hash of argument+hashMessage :: ByteArrayAccess ba => ba -> Msg+hashMessage = fromJust . msg . convert . hashWith Keccak_256++-- | Sign message with Ethereum private key+ecsign :: ByteArrayAccess message+ => SecKey+ -- ^ Private key+ -> message+ -- ^ Message content+ -> CompactRecSig+ -- ^ Signature+ecsign key = exportCompactRecSig . signRecMsg key . hashMessage++-- | Recover message signer Ethereum address+ecrecover :: ByteArrayAccess message+ => CompactRecSig+ -- ^ Signature+ -> message+ -- ^ Message content+ -> Maybe Address+ -- ^ Message signer address+ecrecover sig message = do+ sig' <- importCompactRecSig sig+ fromPubKey <$> recover sig' (hashMessage message)
+ src/Data/ByteArray/HexString.hs view
@@ -0,0 +1,71 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings #-}++-- |+-- Module : Data.ByteArray.HexString+-- Copyright : Alexander Krupenkin 2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : unportable+--+-- Hex string data type and useful functions.+--++module Data.ByteArray.HexString where++import Data.Aeson (FromJSON (..), ToJSON (..),+ Value (String), withText)+import Data.ByteArray (ByteArray, ByteArrayAccess, convert)+import qualified Data.ByteArray as BA (drop, take)+import Data.ByteArray.Encoding (Base (Base16), convertFromBase,+ convertToBase)+import Data.ByteString (ByteString)+import Data.Monoid (Monoid, (<>))+import Data.Semigroup (Semigroup)+import Data.String (IsString (..))+import Data.Text (Text)+import Data.Text.Encoding (decodeUtf8, encodeUtf8)++-- | Represents a Hex string. Guarantees that all characters it contains+-- are valid hex characters.+newtype HexString = HexString { unHexString :: ByteString }+ deriving (Eq, Ord, Semigroup, Monoid, ByteArrayAccess, ByteArray)++instance Show HexString where+ show = ("HexString " ++) . show . toText++instance IsString HexString where+ fromString = hexString' . fromString+ where+ hexString' :: ByteString -> HexString+ hexString' = either error id . hexString++instance FromJSON HexString where+ parseJSON = withText "HexString" $ either fail pure . hexString . encodeUtf8++instance ToJSON HexString where+ toJSON = String . toText++-- | Smart constructor which validates that all the text are actually+-- have `0x` prefix, hexadecimal characters and length is even.+hexString :: ByteArray ba => ba -> Either String HexString+hexString bs+ | BA.take 2 bs == hexStart = HexString <$> bs'+ | otherwise = Left "Hex string should start from '0x'"+ where+ hexStart = convert ("0x" :: ByteString)+ bs' = convertFromBase Base16 (BA.drop 2 bs)++-- | Reads a raw bytes and converts to hex representation.+fromBytes :: ByteArrayAccess ba => ba -> HexString+fromBytes = HexString . convert++-- | Access to the raw bytes of 'HexString'.+toBytes :: ByteArray ba => HexString -> ba+toBytes = convert . unHexString++-- | Access to a 'Text' representation of the 'HexString'+toText :: HexString -> Text+toText = ("0x" <>) . decodeUtf8 . convertToBase Base16 . unHexString
+ src/Data/Solidity/Abi.hs view
@@ -0,0 +1,68 @@+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeFamilies #-}++-- |+-- Module : Data.Solidity.Abi+-- Copyright : Alexander Krupenkin 2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : noportable+--+-- The Application Binary Interface is the standard way to interact with contracts+-- in the Ethereum ecosystem, both from outside the blockchain and for contract-to-contract+-- interaction. Data is encoded according to its type, as described in this specification.+-- The encoding is not self describing and thus requires a schema in order to decode.+--++module Data.Solidity.Abi where++import Data.Proxy (Proxy)+import Data.Serialize (Get, Putter)+import Generics.SOP (Generic, Rep, from, to)++-- | A class for abi encoding datatype descriptions+class AbiType a where+ isDynamic :: Proxy a -> Bool++-- | A class for encoding datatypes to their abi encoding+--+-- If your compiler has support for the @DeriveGeneric@ and+-- @DefaultSignatures@ language extensions (@ghc >= 7.2.1@),+-- the 'abiPut' method will have default generic implementations.+--+-- To use this option, simply add a @deriving 'Generic'@ clause+-- to your datatype and declare a 'AbiPut' instance for it without+-- giving a definition for 'abiPut'.+--+class AbiType a => AbiPut a where+ abiPut :: Putter a++ default abiPut :: (Generic a, Rep a ~ rep, GenericAbiPut rep) => Putter a+ abiPut = gAbiPut . from++-- | A class for encoding generically composed datatypes to their abi encoding+class GenericAbiPut a where+ gAbiPut :: Putter a++-- | A class for decoding datatypes from their abi encoding+--+-- If your compiler has support for the @DeriveGeneric@ and+-- @DefaultSignatures@ language extensions (@ghc >= 7.2.1@),+-- the 'abiGet' method will have default generic implementations.+--+-- To use this option, simply add a @deriving 'Generic'@ clause+-- to your datatype and declare a 'AbiGet' instance for it without+-- giving a definition for 'abiGet'.+--+class AbiType a => AbiGet a where+ abiGet :: Get a++ default abiGet :: (Generic a, Rep a ~ rep, GenericAbiGet rep) => Get a+ abiGet = to <$> gAbiGet++-- | A class for decoding generically composed datatypes from their abi encoding+class GenericAbiGet a where+ gAbiGet :: Get a
+ src/Data/Solidity/Abi/Codec.hs view
@@ -0,0 +1,66 @@+{-# LANGUAGE TypeFamilies #-}++-- |+-- Module : Data.Solidity.Abi.Codec+-- Copyright : Alexander Krupenkin 2017-2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : noportable+--+-- Solidity contract ABI encoding functions.+--++module Data.Solidity.Abi.Codec+ (+ -- * @AbiPut@/@AbiGet@ type class encoding+ encode+ , decode++ -- * Generic encoding+ , encode'+ , decode'+ ) where++import Data.ByteArray (ByteArray, ByteArrayAccess, convert)+import Data.Serialize (runGet, runPut)+import Generics.SOP (Generic, Rep, from, to)++import Data.Solidity.Abi (AbiGet (..), AbiPut (..),+ GenericAbiGet (..),+ GenericAbiPut (..))+import Data.Solidity.Abi.Generic ()++-- | Encode datatype to Ethereum Abi-encoding+encode :: (AbiPut a, ByteArray ba)+ => a+ -> ba+{-# INLINE encode #-}+encode = convert . runPut . abiPut++-- | Generic driven version of 'encode'+encode' :: (Generic a,+ Rep a ~ rep,+ GenericAbiPut rep,+ ByteArray ba)+ => a+ -> ba+{-# INLINE encode' #-}+encode' = convert . runPut . gAbiPut . from++-- | Decode datatype from Ethereum Abi-encoding+decode :: (ByteArrayAccess ba, AbiGet a)+ => ba+ -> Either String a+{-# INLINE decode #-}+decode = runGet abiGet . convert++-- | Generic driven version of 'decode'+decode' :: (Generic a,+ Rep a ~ rep,+ GenericAbiGet rep,+ ByteArrayAccess ba)+ => ba+ -> Either String a+decode' = runGet (to <$> gAbiGet) . convert
+ src/Data/Solidity/Abi/Generic.hs view
@@ -0,0 +1,123 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeInType #-}+{-# LANGUAGE TypeOperators #-}++-- |+-- Module : Data.Solidity.Abi.Generic+-- Copyright : Alexander Krupenkin 2017-2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : noportable+--+-- This module is internal, the purpose is to define helper classes and functions+-- to assist in encoding and decoding Solidity types for function calls and events.+-- The user of this library should have no need to use this directly in application code.+--++module Data.Solidity.Abi.Generic () where++import qualified Data.ByteString.Lazy as LBS+import Data.Int (Int64)+import qualified Data.List as L+import Data.Monoid ((<>))+import Data.Proxy (Proxy (..))+import Data.Serialize (Get, Put)+import Data.Serialize.Get (bytesRead, lookAheadE, skip)+import Data.Serialize.Put (runPutLazy)+import Generics.SOP (I (..), NP (..), NS (..), SOP (..))++import Data.Solidity.Abi (AbiGet (..), AbiPut (..), AbiType (..),+ GenericAbiGet (..), GenericAbiPut (..))+import Data.Solidity.Prim.Int (getWord256, putWord256)++data EncodedValue =+ EncodedValue { order :: Int64+ , offset :: Maybe Int64+ , encoding :: Put+ }++instance Eq EncodedValue where+ ev1 == ev2 = order ev1 == order ev2++instance Ord EncodedValue where+ compare ev1 ev2 = order ev1 `compare` order ev2++combineEncodedValues :: [EncodedValue] -> Put+combineEncodedValues encodings =+ let sortedEs = adjust headsOffset $ L.sort encodings+ encodings' = addTailOffsets headsOffset [] sortedEs+ in let heads = foldl (\acc EncodedValue{..} -> case offset of+ Nothing -> acc <> encoding+ Just o -> acc <> putWord256 (fromIntegral o)+ ) mempty encodings'+ tails = foldl (\acc EncodedValue{..} -> case offset of+ Nothing -> acc+ Just _ -> acc <> encoding+ ) mempty encodings'+ in heads <> tails+ where+ adjust :: Int64 -> [EncodedValue] -> [EncodedValue]+ adjust n = map (\ev -> ev {offset = (+) n <$> offset ev})+ addTailOffsets :: Int64 -> [EncodedValue] -> [EncodedValue] -> [EncodedValue]+ addTailOffsets init' acc es = case es of+ [] -> reverse acc+ (e : tail') -> case offset e of+ Nothing -> addTailOffsets init' (e : acc) tail'+ Just _ -> addTailOffsets init' (e : acc) (adjust (LBS.length . runPutLazy . encoding $ e) tail')+ headsOffset :: Int64+ headsOffset = foldl (\acc e -> case offset e of+ Nothing -> acc + (LBS.length . runPutLazy . encoding $ e)+ Just _ -> acc + 32+ ) 0 encodings++class AbiData a where+ _serialize :: [EncodedValue] -> a -> [EncodedValue]++instance AbiData (NP f '[]) where+ _serialize encoded _ = encoded++instance (AbiType b, AbiPut b, AbiData (NP I as)) => AbiData (NP I (b :as)) where+ _serialize encoded (I b :* a) =+ if isDynamic (Proxy :: Proxy b)+ then _serialize (dynEncoding : encoded) a+ else _serialize (staticEncoding : encoded) a+ where+ staticEncoding = EncodedValue { encoding = abiPut b+ , offset = Nothing+ , order = 1 + (fromInteger . toInteger . L.length $ encoded)+ }+ dynEncoding = EncodedValue { encoding = abiPut b+ , offset = Just 0+ , order = 1 + (fromInteger . toInteger . L.length $ encoded)+ }++instance AbiData (NP f as) => GenericAbiPut (SOP f '[as]) where+ gAbiPut (SOP (Z a)) = combineEncodedValues $ _serialize [] a+ gAbiPut _ = error "Impossible branch"++instance GenericAbiGet (NP f '[]) where+ gAbiGet = return Nil++instance (AbiGet a, GenericAbiGet (NP I as)) => GenericAbiGet (NP I (a : as)) where+ gAbiGet = (:*) <$> (I <$> factorParser) <*> gAbiGet++instance GenericAbiGet (NP f as) => GenericAbiGet (SOP f '[as]) where+ gAbiGet = SOP . Z <$> gAbiGet++factorParser :: forall a . AbiGet a => Get a+factorParser+ | not $ isDynamic (Proxy :: Proxy a) = abiGet+ | otherwise = do+ dataOffset <- fromIntegral <$> getWord256+ currentOffset <- bytesRead+ Left x <- lookAheadE $ do+ skip (dataOffset - currentOffset)+ Left <$> abiGet+ return x
+ src/Data/Solidity/Event.hs view
@@ -0,0 +1,142 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}++-- |+-- Module : Data.Solidity.Event+-- Copyright : Alexander Krupenkin 2017-2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : unportable+--+-- This module is internal, the purpose is to define+-- helper classes and functions to assist in event decoding.+-- The user of this library should have no need to use+-- this directly in application code.+--++module Data.Solidity.Event+ (+ DecodeEvent(..)+ , IndexedEvent(..)+ ) where++import Data.ByteArray (ByteArrayAccess)+import Data.Proxy (Proxy (..))+import Generics.SOP (Generic, I (..), NP (..),+ NS (..), Rep, SOP (..), from, to)++import Data.Solidity.Abi (AbiGet)+import Data.Solidity.Abi.Codec (decode)+import Data.Solidity.Event.Internal+import Network.Ethereum.Api.Types (Change (..))++-- | Indexed event args come back in as a list of encoded values. 'ArrayParser'+-- | is used to decode these values so that they can be used to reconstruct the+-- | entire decoded event.+class ArrayParser a where+ arrayParser :: ByteArrayAccess ba+ => [ba]+ -> Either String a++instance ArrayParser (NP f '[]) where+ arrayParser _ = Right Nil++instance (ArrayParser (NP I as), AbiGet a)+ => ArrayParser (NP I (a : as)) where+ arrayParser [] = Left "Empty"+ arrayParser (a : as) = do+ a' <- decode a+ as' <- arrayParser as+ return $ I a' :* as'++instance ArrayParser (NP f as) => ArrayParser (SOP f '[as]) where+ arrayParser = fmap (SOP . Z) . arrayParser++genericArrayParser :: ( Generic a+ , Rep a ~ rep+ , ArrayParser rep+ , ByteArrayAccess ba+ )+ => [ba]+ -> Either String a+genericArrayParser = fmap to . arrayParser++--------------------------------------------------------------------------------+-- Event Parsing+--------------------------------------------------------------------------------++data Event i ni = Event i ni++-- | 'parseChange' decodes both the indexed and non-indexed event components.+parseChange :: ( Generic i+ , Rep i ~ irep+ , ArrayParser irep+ , AbiGet ni+ )+ => Change+ -> Bool+ -- ^ is anonymous event+ -> Either String (Event i ni)+parseChange change anonymous =+ Event <$> genericArrayParser topics <*> decode data_+ where+ topics | anonymous = changeTopics change+ | otherwise = tail (changeTopics change)+ data_ = changeData change++class IndexedEvent i ni e | e -> i ni where+ isAnonymous :: Proxy e -> Bool++-- | 'CombineChange' is a class which indicates that given event components of types 'i'+-- | and 'ni', we can construct an event of type 'e'. The functional dependency is valid+-- | becasue of how the template haskell generates the event types.+class CombineChange i ni e | e -> i ni where+ combineChange :: i -> ni -> e++instance ( Generic i+ , Rep i ~ irep+ , Generic ni+ , Rep ni ~ nirep+ , Generic e+ , Rep e ~ erep+ , HListRep irep hli+ , HListRep nirep hlni+ , MergeIndexedArguments hli hlni+ , MergeIndexedArguments' hli hlni ~ hle+ , HListRep erep hle+ , IndexedEvent i ni e+ ) => CombineChange i ni e where+ combineChange i ni =+ let hli = toHList . from $ i+ hlni = toHList . from $ ni+ hle = mergeIndexedArguments hli hlni+ in to . fromHList $ hle++class DecodeEvent i ni e | e -> i ni where+ decodeEvent :: Change -> Either String e++instance ( IndexedEvent i ni e+ , Generic i+ , Rep i ~ SOP I '[hli]+ , AbiGet ni+ , Generic ni+ , Rep ni ~ SOP I '[hlni]+ , Generic e+ , Rep e ~ SOP I '[hle]+ , CombineChange i ni e+ , ArrayParser (SOP I '[hli])+ ) => DecodeEvent i ni e where+ decodeEvent change = do+ let anonymous = isAnonymous (Proxy :: Proxy e)+ (Event i ni :: Event i ni) <- parseChange change anonymous+ return $ combineChange i ni
+ src/Data/Solidity/Event/Internal.hs view
@@ -0,0 +1,136 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeInType #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}++-- |+-- Module : Data.Solidity.Event.Internal+-- Copyright : Alexander Krupenkin 2017-2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : unportable+--+-- This module is internal, the purpose is to define helper classes and types+-- to assist in event decoding. The user of this library should have no need to use+-- this directly in application code.+--++module Data.Solidity.Event.Internal where++import Data.Kind (Type)+import Data.Proxy (Proxy (..))+import Data.Tagged (Tagged (..))+import Generics.SOP (I (..), NP (..), NS (..), SOP (..))+import GHC.TypeLits (CmpNat)++data HList :: [Type] -> Type where+ HNil :: HList '[]+ (:<) :: a -> HList as -> HList (a : as)++infixr 0 :<++-- | Generic representation to HList representation+class HListRep a xs | a -> xs, a -> xs where+ toHList :: a -> HList xs+ fromHList :: HList xs -> a++instance HListRep (NP I '[]) '[] where+ toHList _ = HNil+ fromHList _ = Nil++instance HListRep (NP I as) as => HListRep (NP I (a:as)) (a:as) where+ toHList (I a :* rest) = a :< toHList rest+ fromHList (a :< rest) = I a :* fromHList rest++instance HListRep (NP f as') as => HListRep (SOP f '[as']) as where+ toHList (SOP (Z rep)) = toHList rep+ toHList _ = error "Impossible branch"+ fromHList = SOP . Z . fromHList++-- | Sort a Tagged HList+class Sort (xs :: [Type]) where+ type Sort' xs :: [Type]+ sort :: HList xs -> HList (Sort' xs)++instance Sort '[] where+ type Sort' '[] = '[]+ sort HNil = HNil++instance (Sort xs, Insert x (Sort' xs)) => Sort (x : xs) where+ type Sort' (x : xs) = Insert' x (Sort' xs)+ sort (x :< xs) = insert x (sort xs)++class Insert (x :: Type) (xs :: [Type]) where+ type Insert' x xs :: [Type]+ insert :: x -> HList xs -> HList (Insert' x xs)++instance Insert x '[] where+ type Insert' x '[] = '[x]+ insert x HNil = x :< HNil++instance InsertCmp (CmpNat n m) (Tagged n x) (Tagged m y) ys => Insert (Tagged n x) (Tagged m y : ys) where+ type Insert' (Tagged n x) (Tagged m y : ys) = InsertCmp' (CmpNat n m) (Tagged n x) (Tagged m y) ys+ insert (x :: Tagged n x) ((y :: Tagged m y) :< ys) = insertCmp (Proxy :: Proxy (CmpNat n m)) x y ys++class InsertCmp (b :: Ordering) (x :: Type) (y :: Type) (ys :: [Type]) where+ type InsertCmp' b x y ys :: [Type]+ insertCmp :: Proxy (b :: Ordering) -> x -> y -> HList ys -> HList (InsertCmp' b x y ys)++instance InsertCmp 'LT x y ys where+ type InsertCmp' 'LT x y ys = x : (y : ys)+ insertCmp _ x y ys = x :< y :< ys++instance Insert x ys => InsertCmp 'GT x y ys where+ type InsertCmp' 'GT x y ys = y : Insert' x ys+ insertCmp _ x y ys = y :< insert x ys++-- | Unwrap all the Tagged items in an HList+class UnTag t where+ type UnTag' t :: [Type]+ unTag :: HList t -> HList (UnTag' t)++instance UnTag '[] where+ type UnTag' '[] = '[]+ unTag a = a++instance UnTag ts => UnTag (Tagged n a : ts) where+ type UnTag' (Tagged n a : ts) = a : UnTag' ts+ unTag (Tagged a :< ts) = a :< unTag ts++class HListMerge (as :: [Type]) (bs :: [Type]) where+ type Concat as bs :: [Type]+ mergeHList :: HList as -> HList bs -> HList (Concat as bs)++instance HListMerge '[] bs where+ type Concat '[] bs = bs+ mergeHList _ bs = bs++instance HListMerge as bs => HListMerge (a : as) bs where+ type Concat (a : as) bs = a : Concat as bs+ mergeHList (a :< as) bs = a :< mergeHList as bs++class HListMergeSort as bs where+ type MergeSort' as bs :: [Type]+ mergeSortHList :: HList as -> HList bs -> HList (MergeSort' as bs)++instance (HListMerge as bs, Concat as bs ~ cs, Sort cs, Sort' cs ~ cs') => HListMergeSort as bs where+ type MergeSort' as bs = Sort' (Concat as bs)+ mergeSortHList as bs = sort $ (mergeHList as bs :: HList cs)++class MergeIndexedArguments as bs where+ type MergeIndexedArguments' as bs :: [Type]+ mergeIndexedArguments :: HList as -> HList bs -> HList (MergeIndexedArguments' as bs)++instance (HListMergeSort as bs, MergeSort' as bs ~ cs, UnTag cs, UnTag cs' ~ ds) => MergeIndexedArguments as bs where+ type MergeIndexedArguments' as bs = (UnTag' (MergeSort' as bs))+ mergeIndexedArguments as bs = unTag $ mergeSortHList as bs
+ src/Data/Solidity/Prim.hs view
@@ -0,0 +1,30 @@+-- |+-- Module : Data.Solidity.Prim+-- Copyright : Alexander Krupenkin 2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : noportable+--+-- Solidity primitive data types.+--++module Data.Solidity.Prim+ (+ Address+ , Bytes+ , BytesN+ , IntN+ , UIntN+ , ListN+ ) where++import Data.Solidity.Prim.Address (Address)+import Data.Solidity.Prim.Bool ()+import Data.Solidity.Prim.Bytes (Bytes, BytesN)+import Data.Solidity.Prim.Int (IntN, UIntN)+import Data.Solidity.Prim.List (ListN)+import Data.Solidity.Prim.String ()+import Data.Solidity.Prim.Tagged ()+import Data.Solidity.Prim.Tuple ()
+ src/Data/Solidity/Prim/Address.hs view
@@ -0,0 +1,123 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}++-- |+-- Module : Data.Solidity.Prim.Address+-- Copyright : Alexander Krupenkin 2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : noportable+--+-- Ethreum account address.+--++module Data.Solidity.Prim.Address+ (+ -- * The @Address@ type+ Address++ -- * Hex string encoding+ , toHexString+ , fromHexString++ -- * Public key to @Address@ convertor+ , fromPubKey++ -- * EIP55 Mix-case checksum address encoding+ , toChecksum+ , verifyChecksum+ ) where++import Control.Monad ((<=<))+import Crypto.Hash (Keccak_256 (..), hashWith)+import Crypto.Secp256k1 (PubKey, exportPubKey)+import Data.Aeson (FromJSON (..), ToJSON (..))+import Data.Bits ((.&.))+import Data.Bool (bool)+import Data.ByteArray (convert, zero)+import qualified Data.ByteArray as BA (drop)+import Data.ByteString (ByteString)+import qualified Data.ByteString as BS (take, unpack)+import qualified Data.ByteString.Char8 as C8 (drop, length, pack, unpack)+import qualified Data.Char as C (toLower, toUpper)+import Data.Default (Default (..))+import Data.Monoid ((<>))+import Data.String (IsString (..))+import Data.Text.Encoding as T (encodeUtf8)+import Generics.SOP (Generic)+import qualified GHC.Generics as GHC (Generic)++import Data.ByteArray.HexString (HexString, fromBytes, toBytes,+ toText)+import Data.Solidity.Abi (AbiGet (..), AbiPut (..),+ AbiType (..))+import Data.Solidity.Abi.Codec (decode, encode)+import Data.Solidity.Prim.Int (UIntN)++-- | Ethereum account address+newtype Address = Address { unAddress :: UIntN 160 }+ deriving (Eq, Ord, GHC.Generic)++instance Generic Address++instance Default Address where+ def = Address 0++instance Show Address where+ show = show . toChecksum . T.encodeUtf8 . toText . toHexString++instance IsString Address where+ fromString = either error id . fromHexString . fromString++instance AbiType Address where+ isDynamic _ = False++instance AbiGet Address where+ abiGet = Address <$> abiGet++instance AbiPut Address where+ abiPut = abiPut . unAddress++instance FromJSON Address where+ parseJSON = (either fail pure . fromHexString) <=< parseJSON++instance ToJSON Address where+ toJSON = toJSON . toHexString++-- | Derive address from secp256k1 public key+fromPubKey :: PubKey -> Address+fromPubKey key =+ case decode $ zero 12 <> BA.drop 12 (sha3 key) of+ Right a -> a+ Left e -> error $ "Impossible error: " ++ e+ where+ sha3 :: PubKey -> ByteString+ sha3 = convert . hashWith Keccak_256 . BA.drop 1 . exportPubKey False++-- | Decode address from hex string+fromHexString :: HexString -> Either String Address+fromHexString bs+ | bslen == 20 = decode (zero 12 <> toBytes bs :: ByteString)+ | otherwise = Left $ "Incorrect address length: " ++ show bslen+ where bslen = C8.length (toBytes bs)++-- | Encode address to hex string+toHexString :: Address -> HexString+toHexString = fromBytes . C8.drop 12 . encode++-- | Encode address with mixed-case checksum+-- https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md+toChecksum :: ByteString -> ByteString+toChecksum addr = ("0x" <>) . C8.pack $ zipWith ($) upcaseVector lower+ where+ upcaseVector = (>>= fourthBits) . BS.unpack . BS.take 20 . convert $ hashWith Keccak_256 (C8.pack lower)+ fourthBits n = bool id C.toUpper <$> [n .&. 0x80 /= 0, n .&. 0x08 /= 0]+ lower = drop 2 . fmap C.toLower . C8.unpack $ addr++-- | Verify mixed-case address checksum+-- https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md+verifyChecksum :: ByteString -> Bool+verifyChecksum = toChecksum >>= (==)
+ src/Data/Solidity/Prim/Bool.hs view
@@ -0,0 +1,25 @@+-- |+-- Module : Data.Solidity.Prim.Bool+-- Copyright : Alexander Krupenkin 2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : noportable+--+-- Ethereum Abi boolean type.+--++module Data.Solidity.Prim.Bool () where++import Data.Solidity.Abi (AbiGet (..), AbiPut (..), AbiType (..))+import Data.Solidity.Prim.Int (getWord256, putWord256)++instance AbiType Bool where+ isDynamic _ = False++instance AbiGet Bool where+ abiGet = toEnum . fromIntegral <$> getWord256++instance AbiPut Bool where+ abiPut = putWord256 . fromIntegral . fromEnum
+ src/Data/Solidity/Prim/Bytes.hs view
@@ -0,0 +1,126 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}++-- |+-- Module : Data.Solidity.Prim.Bytes+-- Copyright : Alexander Krupenkin 2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : noportable+--+-- Bytes and BytesN primitive types.+--++module Data.Solidity.Prim.Bytes+ (+ -- * The dynamic length @Bytes@ type+ Bytes++ -- * The fixed length @BytesN@ type+ , BytesN+ ) where++import Control.Monad (unless)+import Data.Aeson (FromJSON (..), ToJSON (..),+ Value (String))+import Data.ByteArray (Bytes, convert, length, zero)+import Data.ByteArray.Encoding (Base (Base16), convertFromBase,+ convertToBase)+import Data.ByteArray.Sized (SizedByteArray, unSizedByteArray,+ unsafeFromByteArrayAccess)+import qualified Data.ByteArray.Sized as S (take)+import Data.ByteString (ByteString)+import qualified Data.ByteString.Char8 as C8+import Data.Monoid ((<>))+import Data.Proxy (Proxy (..))+import Data.Serialize (Get, Putter, getBytes, putByteString)+import Data.String (IsString (..))+import qualified Data.Text as T (append, drop, take)+import Data.Text.Encoding (decodeUtf8, encodeUtf8)+import GHC.TypeLits+import Prelude hiding (length)++import Data.Solidity.Abi (AbiGet (..), AbiPut (..),+ AbiType (..))+import Data.Solidity.Prim.Int (getWord256, putWord256)++instance AbiType ByteString where+ isDynamic _ = True++instance AbiGet ByteString where+ abiGet = abiGetByteString++instance AbiPut ByteString where+ abiPut = abiPutByteString++instance AbiType Bytes where+ isDynamic _ = True++instance AbiGet Bytes where+ abiGet = convert <$> abiGetByteString++instance AbiPut Bytes where+ abiPut = abiPutByteString . convert++instance IsString Bytes where+ fromString ('0' : 'x' : hex) = either error id $ convertFromBase Base16 (C8.pack hex)+ fromString str = convert (C8.pack str)++instance FromJSON Bytes where+ parseJSON (String hex)+ | T.take 2 hex == "0x" =+ either fail pure $ convertFromBase Base16 $ encodeUtf8 $ T.drop 2 hex+ | otherwise = fail "Hex string should have '0x' prefix"+ parseJSON _ = fail "Bytes should be encoded as hex string"++instance ToJSON Bytes where+ toJSON = toJSON . T.append "0x" . decodeUtf8 . convertToBase Base16++-- | Sized byte array with fixed length in bytes+type BytesN n = SizedByteArray n Bytes++instance (n <= 32) => AbiType (BytesN n) where+ isDynamic _ = False++instance (KnownNat n, n <= 32) => AbiGet (BytesN n) where+ abiGet = do+ ba <- unsafeFromByteArrayAccess <$> getBytes 32+ return $ S.take (ba :: BytesN 32)++instance (KnownNat n, n <= 32) => AbiPut (BytesN n) where+ abiPut ba = putByteString $ convert ba <> zero (32 - len)+ where len = fromIntegral $ natVal (Proxy :: Proxy n)++instance (KnownNat n, n <= 32) => IsString (BytesN n) where+ fromString s = unsafeFromByteArrayAccess padded+ where bytes = fromString s :: Bytes+ len = fromIntegral $ natVal (Proxy :: Proxy n)+ padded = bytes <> zero (len - length bytes)++instance (KnownNat n, n <= 32) => FromJSON (BytesN n) where+ parseJSON v = do ba <- parseJSON v+ return $ unsafeFromByteArrayAccess (ba :: Bytes)++instance (KnownNat n, n <= 32) => ToJSON (BytesN n) where+ toJSON ba = toJSON (unSizedByteArray ba :: Bytes)++abiGetByteString :: Get ByteString+abiGetByteString = do+ len <- fromIntegral <$> getWord256+ if len == 0+ then return ""+ else getBytes len++abiPutByteString :: Putter ByteString+abiPutByteString bs = do+ putWord256 $ fromIntegral len+ unless (len == 0) $+ putByteString $ bs <> zero (32 - len `mod` 32)+ where len = length bs
+ src/Data/Solidity/Prim/Int.hs view
@@ -0,0 +1,139 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}++-- |+-- Module : Data.Solidity.Prim.Int+-- Copyright : Alexander Krupenkin 2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : noportable+--+-- Ethereum Abi intN and uintN types.+--++module Data.Solidity.Prim.Int+ (+ -- * The @IntN@ type+ IntN++ -- * The @UIntN@ type+ , UIntN++ -- * @Word256@ serializers+ , getWord256+ , putWord256+ ) where++import qualified Basement.Numerical.Number as Basement (toInteger)+import Basement.Types.Word256 (Word256 (Word256))+import qualified Basement.Types.Word256 as Basement (quot, rem)+import Data.Bits (Bits (testBit), (.&.))+import Data.Proxy (Proxy (..))+import Data.Serialize (Get, Putter, Serialize (get, put))+import GHC.Generics (Generic)+import GHC.TypeLits++import Data.Solidity.Abi (AbiGet (..), AbiPut (..),+ AbiType (..))++instance Real Word256 where+ toRational = toRational . toInteger++instance Integral Word256 where+ toInteger = Basement.toInteger+ quotRem a b = (Basement.quot a b, Basement.rem a b)++-- | Unsigned integer with fixed length in bits+newtype UIntN (n :: Nat) = UIntN { unUIntN :: Word256 }+ deriving (Eq, Ord, Enum, Bits, Generic)++instance (KnownNat n, n <= 256) => Num (UIntN n) where+ a + b = fromInteger (toInteger a + toInteger b)+ a - b = fromInteger (toInteger a - toInteger b)+ a * b = fromInteger (toInteger a * toInteger b)+ abs = fromInteger . abs . toInteger+ negate = fromInteger . negate . toInteger+ signum = fromInteger . signum . toInteger+ fromInteger x+ | x >= 0 = mask $ UIntN (fromInteger x)+ | otherwise = mask $ UIntN (fromInteger $ 2 ^ 256 + x)+ where+ mask = (maxBound .&.) :: UIntN n -> UIntN n++instance (KnownNat n, n <= 256) => Show (UIntN n) where+ show = show . unUIntN++instance (KnownNat n, n <= 256) => Bounded (UIntN n) where+ minBound = UIntN 0+ maxBound = UIntN $ 2 ^ natVal (Proxy :: Proxy n) - 1++instance (KnownNat n, n <= 256) => Real (UIntN n) where+ toRational = toRational . toInteger++instance (KnownNat n, n <= 256) => Integral (UIntN n) where+ toInteger = toInteger . unUIntN+ quotRem (UIntN a) (UIntN b) = (UIntN $ quot a b, UIntN $ rem a b)++instance (n <= 256) => AbiType (UIntN n) where+ isDynamic _ = False++instance (n <= 256) => AbiGet (UIntN n) where+ abiGet = UIntN <$> getWord256++instance (n <= 256) => AbiPut (UIntN n) where+ abiPut = putWord256 . unUIntN++-- Signed integer with fixed length in bits+newtype IntN (n :: Nat) = IntN { unIntN :: Word256 }+ deriving (Eq, Ord, Enum, Bits, Generic)++instance (KnownNat n, n <= 256) => Show (IntN n) where+ show = show . toInteger++instance (KnownNat n, n <= 256) => Bounded (IntN n) where+ minBound = IntN $ negate $ 2 ^ (natVal (Proxy :: Proxy (n :: Nat)) - 1)+ maxBound = IntN $ 2 ^ (natVal (Proxy :: Proxy (n :: Nat)) - 1) - 1++instance (KnownNat n, n <= 256) => Num (IntN n) where+ a + b = fromInteger (toInteger a + toInteger b)+ a - b = fromInteger (toInteger a - toInteger b)+ a * b = fromInteger (toInteger a * toInteger b)+ abs = fromInteger . abs . toInteger+ negate = fromInteger . negate . toInteger+ signum = fromInteger . signum . toInteger+ fromInteger x+ | x >= 0 = IntN (fromInteger x)+ | otherwise = IntN (fromInteger $ 2 ^ 256 + x)++instance (KnownNat n, n <= 256) => Real (IntN n) where+ toRational = toRational . toInteger++instance (KnownNat n, n <= 256) => Integral (IntN n) where+ quotRem (IntN a) (IntN b) = (IntN $ quot a b, IntN $ rem a b)+ toInteger x+ | testBit x 255 = toInteger (unIntN x) - 2 ^ 256+ | otherwise = toInteger $ unIntN x++instance (n <= 256) => AbiType (IntN n) where+ isDynamic _ = False++instance (n <= 256) => AbiGet (IntN n) where+ abiGet = IntN <$> getWord256++instance (n <= 256) => AbiPut (IntN n) where+ abiPut = putWord256 . unIntN++putWord256 :: Putter Word256+putWord256 (Word256 a3 a2 a1 a0) =+ put a3 >> put a2 >> put a1 >> put a0++getWord256 :: Get Word256+getWord256 = Word256 <$> get <*> get <*> get <*> get
+ src/Data/Solidity/Prim/List.hs view
@@ -0,0 +1,56 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-}++-- |+-- Module : Data.Solidity.Prim.List+-- Copyright : Alexander Krupenkin 2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : noportable+--+-- Ethereum Abi dynamic and static size vectors based on linked lists.+--++module Data.Solidity.Prim.List+ (+ -- * Fixed size linked list+ ListN+ ) where++import Basement.Nat (NatWithinBound)+import Basement.Sized.List (ListN, toListN_, unListN)+import qualified Basement.Sized.List as SL (mapM_, replicateM)+import Control.Monad (replicateM)+import GHC.Exts (IsList (..))+import GHC.TypeLits (KnownNat)++import Data.Solidity.Abi (AbiGet (..), AbiPut (..), AbiType (..))+import Data.Solidity.Prim.Int (getWord256, putWord256)++instance AbiType [a] where+ isDynamic _ = True++instance AbiPut a => AbiPut [a] where+ abiPut l = do putWord256 $ fromIntegral (length l)+ foldMap abiPut l++instance AbiGet a => AbiGet [a] where+ abiGet = do len <- fromIntegral <$> getWord256+ replicateM len abiGet++instance AbiType (ListN n a) where+ isDynamic _ = False++instance AbiPut a => AbiPut (ListN n a) where+ abiPut = SL.mapM_ abiPut++instance (NatWithinBound Int n, KnownNat n, AbiGet a) => AbiGet (ListN n a) where+ abiGet = SL.replicateM abiGet++instance (NatWithinBound Int n, KnownNat n) => IsList (ListN n a) where+ type Item (ListN n a) = a+ fromList = toListN_+ toList = unListN
+ src/Data/Solidity/Prim/String.hs view
@@ -0,0 +1,29 @@+-- |+-- Module : Data.Solidity.Prim.String+-- Copyright : Alexander Krupenkin 2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : noportable+--+-- Ethereum Abi UTF8-encoded string type.+--++module Data.Solidity.Prim.String where++import Data.Text (Text)+import Data.Text.Encoding (decodeUtf8, encodeUtf8)++import Data.Solidity.Abi (AbiGet (..), AbiPut (..),+ AbiType (..))+import Data.Solidity.Prim.Bytes ()++instance AbiType Text where+ isDynamic _ = True++instance AbiPut Text where+ abiPut = abiPut . encodeUtf8++instance AbiGet Text where+ abiGet = decodeUtf8 <$> abiGet
+ src/Data/Solidity/Prim/Tagged.hs view
@@ -0,0 +1,37 @@+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- |+-- Module : Data.Solidity.Prim.Tagged+-- Copyright : Alexander Krupenkin 2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : noportable+--+-- Ethereum Abi tagged types.+--++module Data.Solidity.Prim.Tagged+ (+ -- * The @Tagged@ type+ Tagged+ ) where++import Data.Proxy (Proxy (..))+import Data.Tagged (Tagged (..))+import Generics.SOP (Generic)++import Data.Solidity.Abi (AbiGet (..), AbiPut (..), AbiType (..))++instance AbiType a => AbiType (Tagged t a) where+ isDynamic _ = isDynamic (Proxy :: Proxy a)++instance AbiPut a => AbiPut (Tagged t a) where+ abiPut (Tagged a) = abiPut a++instance AbiGet a => AbiGet (Tagged t a) where+ abiGet = Tagged <$> abiGet++instance Generic a => Generic (Tagged t a)
+ src/Data/Solidity/Prim/Tuple.hs view
@@ -0,0 +1,38 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TemplateHaskell #-}++-- |+-- Module : Data.Solidity.Prim.Tuple+-- Copyright : Alexander Krupenkin 2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : noportable+--+-- Tuple type abi encoding instances.+--++module Data.Solidity.Prim.Tuple where++import Data.Proxy (Proxy (..))+import Data.Tuple.OneTuple (OneTuple (..))+import Generics.SOP (Generic)+import qualified GHC.Generics as GHC (Generic)++import Data.Solidity.Abi (AbiGet, AbiPut, AbiType (..))+import Data.Solidity.Abi.Generic ()+import Data.Solidity.Prim.Tuple.TH (tupleDecs)++deriving instance GHC.Generic (OneTuple a)+instance Generic (OneTuple a)++instance AbiType a => AbiType (OneTuple a) where+ isDynamic _ = isDynamic (Proxy :: Proxy a)++instance AbiGet a => AbiGet (OneTuple a)+instance AbiPut a => AbiPut (OneTuple a)++$(concat <$> mapM tupleDecs [2..20])
+ src/Data/Solidity/Prim/Tuple/TH.hs view
@@ -0,0 +1,34 @@+{-# LANGUAGE TemplateHaskell #-}++-- |+-- Module : Data.Solidity.Prim.Tuple.TH+-- Copyright : Alexander Krupenkin 2016-2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : noportable+--+-- This module is for internal usage only.+-- It contains tuple abi encoding template haskell generator.+--++module Data.Solidity.Prim.Tuple.TH (tupleDecs) where+++import Control.Monad (replicateM)+import Language.Haskell.TH (DecsQ, Type (VarT), appT, clause, conT,+ cxt, funD, instanceD, newName, normalB,+ tupleT)++import Data.Solidity.Abi (AbiGet, AbiPut, AbiType (..))++tupleDecs :: Int -> DecsQ+tupleDecs n = do+ vars <- replicateM n $ newName "a"+ let types = fmap (pure . VarT) vars+ sequence $+ [ instanceD (cxt $ map (appT $ conT ''AbiType) types) (appT (conT ''AbiType) (foldl appT (tupleT n) types))+ [funD 'isDynamic [clause [] (normalB [|const False|]) []]]+ , instanceD (cxt $ map (appT $ conT ''AbiGet) types) (appT (conT ''AbiGet) (foldl appT (tupleT n) types)) []+ , instanceD (cxt $ map (appT $ conT ''AbiPut) types) (appT (conT ''AbiPut) (foldl appT (tupleT n) types)) [] ]
src/Data/String/Extra.hs view
@@ -1,6 +1,6 @@ -- | -- Module : Data.String.Extra--- Copyright : Alexander Krupenkin 2016-2018+-- Copyright : Alexander Krupenkin 2016 -- License : BSD3 -- -- Maintainer : mail@akru.me
+ src/Language/Solidity/Abi.hs view
@@ -0,0 +1,284 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- |+-- Module : Data.Solidity.Abi.Json+-- Copyright : Alexander Krupenkin 2016-2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : noportable+--+-- JSON encoded contract ABI parsers.+--++module Language.Solidity.Abi+ (+ -- * Contract ABI declarations+ ContractAbi(..)+ , Declaration(..)+ , FunctionArg(..)+ , EventArg(..)++ -- * Method/Event id encoder+ , signature+ , methodId+ , eventId++ -- * Solidity type parser+ , SolidityType(..)+ , parseSolidityType+ ) where++import Control.Monad (void)+import Crypto.Hash (Digest, Keccak_256, hash)+import Data.Aeson (FromJSON (parseJSON), Options (constructorTagModifier, fieldLabelModifier, sumEncoding),+ SumEncoding (TaggedObject),+ ToJSON (toJSON), defaultOptions)+import Data.Aeson.TH (deriveJSON)+import Data.Monoid ((<>))+import Data.Text (Text)+import qualified Data.Text as T (dropEnd, pack, take, unlines, unpack)+import Data.Text.Encoding (encodeUtf8)+import Text.Parsec (ParseError, char, choice, digit, eof,+ lookAhead, many1, manyTill, optionMaybe,+ parse, string, try, (<|>))+import Text.Parsec.Text (Parser)++import Data.String.Extra (toLowerFirst)++-- | Method argument+data FunctionArg = FunctionArg+ { funArgName :: Text+ -- ^ Argument name+ , funArgType :: Text+ -- ^ Argument type+ } deriving (Show, Eq, Ord)++$(deriveJSON+ (defaultOptions {fieldLabelModifier = toLowerFirst . drop 6})+ ''FunctionArg)++-- | Event argument+data EventArg = EventArg+ { eveArgName :: Text+ -- ^ Argument name+ , eveArgType :: Text+ -- ^ Argument type+ , eveArgIndexed :: Bool+ -- ^ Argument is indexed (e.g. placed on topics of event)+ } deriving (Show, Eq, Ord)++$(deriveJSON+ (defaultOptions {fieldLabelModifier = toLowerFirst . drop 6})+ ''EventArg)++-- | Elementrary contract interface item+data Declaration+ = DConstructor { conInputs :: [FunctionArg] }+ -- ^ Contract constructor+ | DFunction { funName :: Text+ , funConstant :: Bool+ , funInputs :: [FunctionArg]+ , funOutputs :: Maybe [FunctionArg] }+ -- ^ Method+ | DEvent { eveName :: Text+ , eveInputs :: [EventArg]+ , eveAnonymous :: Bool }+ -- ^ Event+ | DFallback { falPayable :: Bool }+ -- ^ Fallback function+ deriving Show++instance Eq Declaration where+ (DConstructor a) == (DConstructor b) = length a == length b+ (DFunction a _ _ _) == (DFunction b _ _ _) = a == b+ (DEvent a _ _) == (DEvent b _ _) = a == b+ (DFallback _) == (DFallback _) = True+ (==) _ _ = False++instance Ord Declaration where+ compare (DConstructor a) (DConstructor b) = compare (length a) (length b)+ compare (DFunction a _ _ _) (DFunction b _ _ _) = compare a b+ compare (DEvent a _ _) (DEvent b _ _) = compare a b+ compare (DFallback _) (DFallback _) = EQ++ compare DConstructor {} DFunction {} = LT+ compare DConstructor {} DEvent {} = LT+ compare DConstructor {} DFallback {} = LT++ compare DFunction {} DConstructor {} = GT+ compare DFunction {} DEvent {} = LT+ compare DFunction {} DFallback {} = LT++ compare DEvent {} DConstructor {} = GT+ compare DEvent {} DFunction {} = GT+ compare DEvent {} DFallback {} = LT++ compare DFallback {} DConstructor {} = GT+ compare DFallback {} DFunction {} = GT+ compare DFallback {} DEvent {} = GT++$(deriveJSON (defaultOptions {+ sumEncoding = TaggedObject "type" "contents"+ , constructorTagModifier = toLowerFirst . drop 1+ , fieldLabelModifier = toLowerFirst . drop 3 })+ ''Declaration)++-- | Contract Abi is a list of method / event declarations+newtype ContractAbi = ContractAbi { unAbi :: [Declaration] }+ deriving (Eq, Ord)++instance FromJSON ContractAbi where+ parseJSON = fmap ContractAbi . parseJSON++instance ToJSON ContractAbi where+ toJSON = toJSON . unAbi++instance Show ContractAbi where+ show (ContractAbi c) = T.unpack $ T.unlines $+ [ "Contract:" ]+ ++ foldMap showConstructor c +++ [ "\tEvents:" ]+ ++ foldMap showEvent c +++ [ "\tMethods:" ]+ ++ foldMap showMethod c++showConstructor :: Declaration -> [Text]+showConstructor x = case x of+ DConstructor{} -> ["\tConstructor " <> signature x]+ _ -> []++showEvent :: Declaration -> [Text]+showEvent x = case x of+ DEvent{} -> ["\t\t" <> signature x]+ _ -> []++showMethod :: Declaration -> [Text]+showMethod x = case x of+ DFunction{} ->+ ["\t\t" <> methodId x <> " " <> signature x]+ _ -> []++-- | Take a signature by given decl, e.g. foo(uint,string)+signature :: Declaration -> Text++signature (DConstructor inputs) = "(" <> args inputs <> ")"+ where+ args :: [FunctionArg] -> Text+ args = T.dropEnd 1 . foldMap (<> ",") . fmap funArgType++signature (DFallback _) = "()"++signature (DFunction name _ inputs _) = name <> "(" <> args inputs <> ")"+ where+ args :: [FunctionArg] -> Text+ args = T.dropEnd 1 . foldMap (<> ",") . fmap funArgType++signature (DEvent name inputs _) = name <> "(" <> args inputs <> ")"+ where+ args :: [EventArg] -> Text+ args = T.dropEnd 1 . foldMap (<> ",") . fmap eveArgType++-- | Localy compute Keccak-256 hash of given text+sha3 :: Text -> Text+{-# INLINE sha3 #-}+sha3 x = T.pack (show digest)+ where digest :: Digest Keccak_256+ digest = hash (encodeUtf8 x)++-- | Generate method selector by given method 'Delcaration'+methodId :: Declaration -> Text+{-# INLINE methodId #-}+methodId = ("0x" <>) . T.take 8 . sha3 . signature++-- | Generate event `topic0` hash by givent event 'Delcaration'+eventId :: Declaration -> Text+{-# INLINE eventId #-}+eventId = ("0x" <>) . sha3 . signature++-- | Solidity types and parsers+data SolidityType =+ SolidityBool+ | SolidityAddress+ | SolidityUint Int+ | SolidityInt Int+ | SolidityString+ | SolidityBytesN Int+ | SolidityBytes+ | SolidityVector [Int] SolidityType+ | SolidityArray SolidityType+ deriving (Eq, Show)++numberParser :: Parser Int+numberParser = read <$> many1 digit++parseUint :: Parser SolidityType+parseUint = do+ _ <- string "uint"+ SolidityUint <$> numberParser++parseInt :: Parser SolidityType+parseInt = do+ _ <- string "int"+ SolidityInt <$> numberParser++parseBool :: Parser SolidityType+parseBool = string "bool" >> pure SolidityBool++parseString :: Parser SolidityType+parseString = string "string" >> pure SolidityString++parseBytes :: Parser SolidityType+parseBytes = do+ _ <- string "bytes"+ mn <- optionMaybe numberParser+ pure $ maybe SolidityBytes SolidityBytesN mn++parseAddress :: Parser SolidityType+parseAddress = string "address" >> pure SolidityAddress++solidityBasicTypeParser :: Parser SolidityType+solidityBasicTypeParser =+ choice [ try parseUint+ , try parseInt+ , try parseAddress+ , try parseBool+ , try parseString+ , parseBytes+ ]++parseVector :: Parser SolidityType+parseVector = do+ s <- solidityBasicTypeParser+ ns <- many1Till lengthParser (lookAhead (void $ string "[]") <|> eof)+ pure $ SolidityVector ns s+ where+ many1Till :: Parser Int -> Parser () -> Parser [Int]+ many1Till p end = do+ a <- p+ as <- manyTill p end+ return (a : as)++ lengthParser = do+ _ <- char '['+ n <- numberParser+ _ <- char ']'+ pure n++parseArray :: Parser SolidityType+parseArray = do+ s <- try (parseVector <* string "[]") <|> (solidityBasicTypeParser <* string "[]")+ pure $ SolidityArray s+++solidityTypeParser :: Parser SolidityType+solidityTypeParser =+ choice [ try parseArray+ , try parseVector+ , solidityBasicTypeParser+ ]++parseSolidityType :: Text -> Either ParseError SolidityType+parseSolidityType = parse solidityTypeParser "Solidity"
+ src/Language/Solidity/Compiler.hs view
@@ -0,0 +1,58 @@+{-# LANGUAGE CPP #-}+#ifdef SOLIDITY_COMPILER+{-# LANGUAGE RecordWildCards #-}+#endif++-- |+-- Module : Language.Solidity.Compiler+-- Copyright : Alexander Krupenkin 2017+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : portable+--+-- Solidity compiler high-level bindings.+--++module Language.Solidity.Compiler where++#ifdef SOLIDITY_COMPILER++import Data.ByteString (ByteString)+import Data.Map (Map)+import Data.Semigroup (Semigroup (..))+import qualified Language.Solidity.Compiler.Foreign as FFI+import System.IO.Unsafe (unsafePerformIO)++-- | Input contract sources+data Sources = Sources+ { sourceMap :: Map ByteString ByteString+ -- ^ Source code map from contract name in keys+ , libraries :: Map ByteString ByteString+ -- ^ Library address map for linking+ , optimization :: Bool+ -- ^ Enable optimization?+ } deriving (Eq, Show)++instance Semigroup Sources where+ a <> b = Sources (sourceMap a `mappend` sourceMap b)+ (libraries a `mappend` libraries b)+ (optimization a || optimization b)++instance Monoid Sources where+ mappend = (<>)+ mempty = Sources mempty mempty False++type Compiled = Map ByteString (ByteString, ByteString)++-- | Compile Solidity contracts+compile :: Sources+ -- ^ Contract sources+ -> Either ByteString Compiled+ -- ^ Error string or compiled contracts ABI and hex+{-# NOINLINE compile #-}+compile Sources{..} = unsafePerformIO $+ FFI.compile sourceMap libraries optimization++#endif
+ src/Language/Solidity/Compiler/Foreign.hsc view
@@ -0,0 +1,106 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE ForeignFunctionInterface #-}++-- |+-- Module : Language.Solidity.Compiler.Foreign+-- Copyright : Alexander Krupenkin 2017+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : unportable+--+-- Ethereum Solidity library FFI.+--++module Language.Solidity.Compiler.Foreign where++#ifdef SOLIDITY_COMPILER+#include <solidity_lite.h>++import Data.Map as M+import Data.ByteString.Char8 as BS+import Data.Typeable (Typeable)+import Foreign.C.String (CString, peekCString, withCString)+import Foreign.C.Types (CInt(..))+import Foreign.Ptr (Ptr)+import Foreign (free)++data Solidity+ deriving Typeable++foreign import ccall unsafe "create" c_create+ :: IO (Ptr Solidity)+foreign import ccall unsafe "destroy" c_destroy+ :: Ptr Solidity -> IO ()+foreign import ccall unsafe "addSource" c_addSource+ :: Ptr Solidity -> CString -> CString -> IO CInt+foreign import ccall unsafe "addLibrary" c_addLibrary+ :: Ptr Solidity -> CString -> CString -> IO CInt+foreign import ccall unsafe "compile" c_compile+ :: Ptr Solidity -> CInt -> IO CInt+foreign import ccall unsafe "abi" c_abi+ :: Ptr Solidity -> CString -> IO CString+foreign import ccall unsafe "binary" c_binary+ :: Ptr Solidity -> CString -> IO CString+foreign import ccall unsafe "errors" c_errors+ :: Ptr Solidity -> IO CString++withSolidity :: (Ptr Solidity -> IO a) -> IO a+{-# INLINE withSolidity #-}+withSolidity f = do+ ptr <- c_create+ r <- f ptr+ c_destroy ptr+ return r++withCStringPair :: (CString -> CString -> IO a) -> (ByteString, ByteString) -> IO a+{-# INLINE withCStringPair #-}+withCStringPair f (a, b) =+ withCString (BS.unpack a) $ \astr ->+ withCString (BS.unpack b) $ \bstr ->+ f astr bstr++addSources :: Ptr Solidity -> Map ByteString ByteString -> IO ()+{-# INLINE addSources #-}+addSources ptr = mapM_ (withCStringPair $ c_addSource ptr) . M.toList++addLibraries :: Ptr Solidity -> Map ByteString ByteString -> IO ()+{-# INLINE addLibraries #-}+addLibraries ptr = mapM_ (withCStringPair $ c_addLibrary ptr) . M.toList++result :: Ptr Solidity -> ByteString -> IO (ByteString, ByteString)+result ptr name =+ withCString (BS.unpack name) $ \cname -> do+ abi <- c_abi ptr cname+ bin <- c_binary ptr cname+ res <- (,) <$> fmap BS.pack (peekCString abi)+ <*> fmap BS.pack (peekCString bin)+ free abi+ free bin+ return res++errors :: Ptr Solidity -> IO ByteString+errors ptr = do+ errs <- c_errors ptr+ res <- BS.pack <$> peekCString errs+ free errs+ return res++compile :: Map ByteString ByteString+ -> Map ByteString ByteString+ -> Bool+ -> IO (Either ByteString (Map ByteString (ByteString, ByteString)))+compile srcs libs opt =+ withSolidity $ \ptr -> do+ addSources ptr srcs+ addLibraries ptr libs+ res <- c_compile ptr optI+ let compiled = sequence $ M.mapWithKey (const . result ptr) srcs+ if res < 0+ then Left <$> errors ptr+ else Right <$> compiled+ where optI | opt = 1+ | otherwise = 0++#endif
− src/Network/Ethereum/ABI/Class.hs
@@ -1,71 +0,0 @@-{-# LANGUAGE DefaultSignatures #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE TypeFamilies #-}---- |--- Module : Network.Ethereum.ABI.Class--- Copyright : Alexander Krupenkin 2016-2018--- License : BSD3------ Maintainer : mail@akru.me--- Stability : experimental--- Portability : noportable------ Ethereum ABI encoding base type classes.-----module Network.Ethereum.ABI.Class (- ABIType(..)- , ABIPut(..)- , ABIGet(..)- , GenericABIPut(..)- , GenericABIGet(..)- ) where--import Data.Proxy (Proxy)-import Data.Serialize (Get, Putter)-import Generics.SOP (Generic, Rep, from, to)---- | A class for abi encoding datatype descriptions-class ABIType a where- isDynamic :: Proxy a -> Bool---- | A class for encoding datatypes to their abi encoding------ If your compiler has support for the @DeriveGeneric@ and--- @DefaultSignatures@ language extensions (@ghc >= 7.2.1@),--- the 'abiPut' method will have default generic implementations.------ To use this option, simply add a @deriving 'Generic'@ clause--- to your datatype and declare a 'ABIPut' instance for it without--- giving a definition for 'abiPut'.----class ABIType a => ABIPut a where- abiPut :: Putter a-- default abiPut :: (Generic a, Rep a ~ rep, GenericABIPut rep) => Putter a- abiPut = gAbiPut . from---- | A class for encoding generically composed datatypes to their abi encoding-class GenericABIPut a where- gAbiPut :: Putter a---- | A class for decoding datatypes from their abi encoding------ If your compiler has support for the @DeriveGeneric@ and--- @DefaultSignatures@ language extensions (@ghc >= 7.2.1@),--- the 'abiGet' method will have default generic implementations.------ To use this option, simply add a @deriving 'Generic'@ clause--- to your datatype and declare a 'ABIGet' instance for it without--- giving a definition for 'abiGet'.----class ABIType a => ABIGet a where- abiGet :: Get a-- default abiGet :: (Generic a, Rep a ~ rep, GenericABIGet rep) => Get a- abiGet = to <$> gAbiGet---- | A class for decoding generically composed datatypes from their abi encoding-class GenericABIGet a where- gAbiGet :: Get a
− src/Network/Ethereum/ABI/Codec.hs
@@ -1,63 +0,0 @@-{-# LANGUAGE TypeFamilies #-}---- |--- Module : Network.Ethereum.ABI.Codec--- Copyright : Alexander Krupenkin 2016-2018--- License : BSD3------ Maintainer : mail@akru.me--- Stability : experimental--- Portability : noportable------ Ethereum ABI encoding codec functions.-----module Network.Ethereum.ABI.Codec (- encode- , decode- , encode'- , decode'- ) where--import Data.ByteArray (ByteArray, ByteArrayAccess,- convert)-import Data.Serialize (runGet, runPut)-import Generics.SOP (Generic, Rep, from, to)--import Network.Ethereum.ABI.Class (ABIGet (..), ABIPut (..),- GenericABIGet (..),- GenericABIPut (..))-import Network.Ethereum.ABI.Generic ()---- | Encode datatype to Ethereum ABI-encoding-encode :: (ABIPut a, ByteArray ba)- => a- -> ba-{-# INLINE encode #-}-encode = convert . runPut . abiPut---- | Generic driven version of 'encode'-encode' :: (Generic a,- Rep a ~ rep,- GenericABIPut rep,- ByteArray ba)- => a- -> ba-{-# INLINE encode' #-}-encode' = convert . runPut . gAbiPut . from---- | Decode datatype from Ethereum ABI-encoding-decode :: (ByteArrayAccess ba, ABIGet a)- => ba- -> Either String a-{-# INLINE decode #-}-decode = runGet abiGet . convert---- | Generic driven version of 'decode'-decode' :: (Generic a,- Rep a ~ rep,- GenericABIGet rep,- ByteArrayAccess ba)- => ba- -> Either String a-decode' = runGet (to <$> gAbiGet) . convert
− src/Network/Ethereum/ABI/Event.hs
@@ -1,144 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE FunctionalDependencies #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE PolyKinds #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE UndecidableInstances #-}---- |--- Module : Network.Ethereum.Web3.Encoding.Event--- Copyright : Alexander Krupenkin 2016-2018--- License : BSD3------ Maintainer : mail@akru.me--- Stability : experimental--- Portability : unportable------ This module is internal, the purpose is to define--- helper classes and functions to assist in event decoding.--- The user of this library should have no need to use--- this directly in application code.-----module Network.Ethereum.ABI.Event(- DecodeEvent(..)- , IndexedEvent(..)- ) where--import Data.ByteArray (ByteArrayAccess)-import Data.Proxy (Proxy (..))-import Generics.SOP (Generic, I (..), NP (..),- NS (..), Rep, SOP (..),- from, to)--import Network.Ethereum.ABI.Class (GenericABIGet)-import Network.Ethereum.ABI.Codec (decode')-import Network.Ethereum.ABI.Event.Internal-import Network.Ethereum.Web3.Types (Change (..))---- | Indexed event args come back in as a list of encoded values. 'ArrayParser'--- | is used to decode these values so that they can be used to reconstruct the--- | entire decoded event.-class ArrayParser a where- arrayParser :: ByteArrayAccess ba- => [ba]- -> Either String a--instance ArrayParser (NP f '[]) where- arrayParser _ = Right Nil--instance (ArrayParser (NP I as), Generic a, Rep a ~ rep, GenericABIGet rep)- => ArrayParser (NP I (a : as)) where- arrayParser [] = Left "Empty"- arrayParser (a : as) = do- a' <- decode' a- as' <- arrayParser as- return $ I a' :* as'--instance ArrayParser (NP f as) => ArrayParser (SOP f '[as]) where- arrayParser = fmap (SOP . Z) . arrayParser--genericArrayParser :: ( Generic a- , Rep a ~ rep- , ArrayParser rep- , ByteArrayAccess ba- )- => [ba]- -> Either String a-genericArrayParser = fmap to . arrayParser------------------------------------------------------------------------------------- Event Parsing-----------------------------------------------------------------------------------data Event i ni = Event i ni---- | 'parseChange' decodes both the indexed and non-indexed event components.-parseChange :: ( Generic i- , Rep i ~ irep- , ArrayParser irep- , Generic ni- , Rep ni ~ nirep- , GenericABIGet nirep- )- => Change- -> Bool- -- ^ is anonymous event- -> Either String (Event i ni)-parseChange change anonymous =- Event <$> genericArrayParser topics <*> decode' data_- where- topics | anonymous = changeTopics change- | otherwise = tail (changeTopics change)- data_ = changeData change--class IndexedEvent i ni e | e -> i ni where- isAnonymous :: Proxy e -> Bool---- | 'CombineChange' is a class which indicates that given event components of types 'i'--- | and 'ni', we can construct an event of type 'e'. The functional dependency is valid--- | becasue of how the template haskell generates the event types.-class CombineChange i ni e | e -> i ni where- combineChange :: i -> ni -> e--instance ( Generic i- , Rep i ~ irep- , Generic ni- , Rep ni ~ nirep- , Generic e- , Rep e ~ erep- , HListRep irep hli- , HListRep nirep hlni- , MergeIndexedArguments hli hlni- , MergeIndexedArguments' hli hlni ~ hle- , HListRep erep hle- , IndexedEvent i ni e- ) => CombineChange i ni e where- combineChange i ni =- let hli = toHList . from $ i- hlni = toHList . from $ ni- hle = mergeIndexedArguments hli hlni- in to . fromHList $ hle--class DecodeEvent i ni e | e -> i ni where- decodeEvent :: Change -> Either String e--instance ( IndexedEvent i ni e- , Generic i- , Rep i ~ SOP I '[hli]- , Generic ni- , Rep ni ~ SOP I '[hlni]- , Generic e- , Rep e ~ SOP I '[hle]- , CombineChange i ni e- , GenericABIGet (SOP I '[hlni])- , ArrayParser (SOP I '[hli])- ) => DecodeEvent i ni e where- decodeEvent change = do- let anonymous = isAnonymous (Proxy :: Proxy e)- (Event i ni :: Event i ni) <- parseChange change anonymous- return $ combineChange i ni
− src/Network/Ethereum/ABI/Event/Internal.hs
@@ -1,136 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE FunctionalDependencies #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE PolyKinds #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeInType #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE UndecidableInstances #-}---- |--- Module : Network.Ethereum.ABI.Event.Internal--- Copyright : Alexander Krupenkin 2016-2018--- License : BSD3------ Maintainer : mail@akru.me--- Stability : experimental--- Portability : unportable------ This module is internal, the purpose is to define helper classes and types--- to assist in event decoding. The user of this library should have no need to use--- this directly in application code.-----module Network.Ethereum.ABI.Event.Internal where--import Data.Kind (Type)-import Data.Proxy (Proxy (..))-import Data.Tagged (Tagged (..))-import Generics.SOP (I (..), NP (..), NS (..), SOP (..))-import GHC.TypeLits (CmpNat)--data HList :: [Type] -> Type where- HNil :: HList '[]- (:<) :: a -> HList as -> HList (a : as)--infixr 0 :<---- | Generic representation to HList representation-class HListRep a xs | a -> xs, a -> xs where- toHList :: a -> HList xs- fromHList :: HList xs -> a--instance HListRep (NP I '[]) '[] where- toHList _ = HNil- fromHList _ = Nil--instance HListRep (NP I as) as => HListRep (NP I (a:as)) (a:as) where- toHList (I a :* rest) = a :< toHList rest- fromHList (a :< rest) = I a :* fromHList rest--instance HListRep (NP f as') as => HListRep (SOP f '[as']) as where- toHList (SOP (Z rep)) = toHList rep- toHList _ = error "Impossible branch"- fromHList = SOP . Z . fromHList---- | Sort a Tagged HList-class Sort (xs :: [Type]) where- type Sort' xs :: [Type]- sort :: HList xs -> HList (Sort' xs)--instance Sort '[] where- type Sort' '[] = '[]- sort HNil = HNil--instance (Sort xs, Insert x (Sort' xs)) => Sort (x : xs) where- type Sort' (x : xs) = Insert' x (Sort' xs)- sort (x :< xs) = insert x (sort xs)--class Insert (x :: Type) (xs :: [Type]) where- type Insert' x xs :: [Type]- insert :: x -> HList xs -> HList (Insert' x xs)--instance Insert x '[] where- type Insert' x '[] = '[x]- insert x HNil = x :< HNil--instance InsertCmp (CmpNat n m) (Tagged n x) (Tagged m y) ys => Insert (Tagged n x) (Tagged m y : ys) where- type Insert' (Tagged n x) (Tagged m y : ys) = InsertCmp' (CmpNat n m) (Tagged n x) (Tagged m y) ys- insert (x :: Tagged n x) ((y :: Tagged m y) :< ys) = insertCmp (Proxy :: Proxy (CmpNat n m)) x y ys--class InsertCmp (b :: Ordering) (x :: Type) (y :: Type) (ys :: [Type]) where- type InsertCmp' b x y ys :: [Type]- insertCmp :: Proxy (b :: Ordering) -> x -> y -> HList ys -> HList (InsertCmp' b x y ys)--instance InsertCmp 'LT x y ys where- type InsertCmp' 'LT x y ys = x : (y : ys)- insertCmp _ x y ys = x :< y :< ys--instance Insert x ys => InsertCmp 'GT x y ys where- type InsertCmp' 'GT x y ys = y : Insert' x ys- insertCmp _ x y ys = y :< insert x ys---- | Unwrap all the Tagged items in an HList-class UnTag t where- type UnTag' t :: [Type]- unTag :: HList t -> HList (UnTag' t)--instance UnTag '[] where- type UnTag' '[] = '[]- unTag a = a--instance UnTag ts => UnTag (Tagged n a : ts) where- type UnTag' (Tagged n a : ts) = a : UnTag' ts- unTag (Tagged a :< ts) = a :< unTag ts--class HListMerge (as :: [Type]) (bs :: [Type]) where- type Concat as bs :: [Type]- mergeHList :: HList as -> HList bs -> HList (Concat as bs)--instance HListMerge '[] bs where- type Concat '[] bs = bs- mergeHList _ bs = bs--instance HListMerge as bs => HListMerge (a : as) bs where- type Concat (a : as) bs = a : Concat as bs- mergeHList (a :< as) bs = a :< mergeHList as bs--class HListMergeSort as bs where- type MergeSort' as bs :: [Type]- mergeSortHList :: HList as -> HList bs -> HList (MergeSort' as bs)--instance (HListMerge as bs, Concat as bs ~ cs, Sort cs, Sort' cs ~ cs') => HListMergeSort as bs where- type MergeSort' as bs = Sort' (Concat as bs)- mergeSortHList as bs = sort $ (mergeHList as bs :: HList cs)--class MergeIndexedArguments as bs where- type MergeIndexedArguments' as bs :: [Type]- mergeIndexedArguments :: HList as -> HList bs -> HList (MergeIndexedArguments' as bs)--instance (HListMergeSort as bs, MergeSort' as bs ~ cs, UnTag cs, UnTag cs' ~ ds) => MergeIndexedArguments as bs where- type MergeIndexedArguments' as bs = (UnTag' (MergeSort' as bs))- mergeIndexedArguments as bs = unTag $ mergeSortHList as bs
− src/Network/Ethereum/ABI/Generic.hs
@@ -1,126 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeInType #-}-{-# LANGUAGE TypeOperators #-}---- |--- Module : Network.Ethereum.ABI.Generic--- Copyright : Alexander Krupenkin 2016-2018--- License : BSD3------ Maintainer : mail@akru.me--- Stability : experimental--- Portability : noportable------ This module is internal, the purpose is to define helper classes and functions--- to assist in encoding and decoding Solidity types for function calls and events.--- The user of this library should have no need to use this directly in application code.-----module Network.Ethereum.ABI.Generic () where--import qualified Data.ByteString.Lazy as LBS-import Data.Int (Int64)-import qualified Data.List as L-import Data.Monoid ((<>))-import Data.Proxy (Proxy (..))-import Data.Serialize (Get, Put)-import Data.Serialize.Get (bytesRead, lookAheadE, skip)-import Data.Serialize.Put (runPutLazy)-import Generics.SOP (I (..), NP (..), NS (..),- SOP (..))--import Network.Ethereum.ABI.Class (ABIGet (..), ABIPut (..),- ABIType (..),- GenericABIGet (..),- GenericABIPut (..))-import Network.Ethereum.ABI.Prim.Int (getWord256, putWord256)--data EncodedValue =- EncodedValue { order :: Int64- , offset :: Maybe Int64- , encoding :: Put- }--instance Eq EncodedValue where- ev1 == ev2 = order ev1 == order ev2--instance Ord EncodedValue where- compare ev1 ev2 = order ev1 `compare` order ev2--combineEncodedValues :: [EncodedValue] -> Put-combineEncodedValues encodings =- let sortedEs = adjust headsOffset $ L.sort encodings- encodings' = addTailOffsets headsOffset [] sortedEs- in let heads = foldl (\acc EncodedValue{..} -> case offset of- Nothing -> acc <> encoding- Just o -> acc <> putWord256 (fromIntegral o)- ) mempty encodings'- tails = foldl (\acc EncodedValue{..} -> case offset of- Nothing -> acc- Just _ -> acc <> encoding- ) mempty encodings'- in heads <> tails- where- adjust :: Int64 -> [EncodedValue] -> [EncodedValue]- adjust n = map (\ev -> ev {offset = (+) n <$> offset ev})- addTailOffsets :: Int64 -> [EncodedValue] -> [EncodedValue] -> [EncodedValue]- addTailOffsets init' acc es = case es of- [] -> reverse acc- (e : tail') -> case offset e of- Nothing -> addTailOffsets init' (e : acc) tail'- Just _ -> addTailOffsets init' (e : acc) (adjust (LBS.length . runPutLazy . encoding $ e) tail')- headsOffset :: Int64- headsOffset = foldl (\acc e -> case offset e of- Nothing -> acc + (LBS.length . runPutLazy . encoding $ e)- Just _ -> acc + 32- ) 0 encodings--class ABIData a where- _serialize :: [EncodedValue] -> a -> [EncodedValue]--instance ABIData (NP f '[]) where- _serialize encoded _ = encoded--instance (ABIType b, ABIPut b, ABIData (NP I as)) => ABIData (NP I (b :as)) where- _serialize encoded (I b :* a) =- if isDynamic (Proxy :: Proxy b)- then _serialize (dynEncoding : encoded) a- else _serialize (staticEncoding : encoded) a- where- staticEncoding = EncodedValue { encoding = abiPut b- , offset = Nothing- , order = 1 + (fromInteger . toInteger . L.length $ encoded)- }- dynEncoding = EncodedValue { encoding = abiPut b- , offset = Just 0- , order = 1 + (fromInteger . toInteger . L.length $ encoded)- }--instance ABIData (NP f as) => GenericABIPut (SOP f '[as]) where- gAbiPut (SOP (Z a)) = combineEncodedValues $ _serialize [] a- gAbiPut _ = error "Impossible branch"--instance GenericABIGet (NP f '[]) where- gAbiGet = return Nil--instance (ABIGet a, GenericABIGet (NP I as)) => GenericABIGet (NP I (a : as)) where- gAbiGet = (:*) <$> (I <$> factorParser) <*> gAbiGet--instance GenericABIGet (NP f as) => GenericABIGet (SOP f '[as]) where- gAbiGet = SOP . Z <$> gAbiGet--factorParser :: forall a . ABIGet a => Get a-factorParser- | not $ isDynamic (Proxy :: Proxy a) = abiGet- | otherwise = do- dataOffset <- fromIntegral <$> getWord256- currentOffset <- bytesRead- Left x <- lookAheadE $ do- skip (dataOffset - currentOffset)- Left <$> abiGet- return x
− src/Network/Ethereum/ABI/Json.hs
@@ -1,280 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell #-}---- |--- Module : Network.Ethereum.ABI.Json--- Copyright : Alexander Krupenkin 2016-2018--- License : BSD3------ Maintainer : mail@akru.me--- Stability : experimental--- Portability : noportable------ JSON encoded contract ABI parsers.-----module Network.Ethereum.ABI.Json (- ContractABI(..)- , Declaration(..)- , FunctionArg(..)- , EventArg(..)- , signature- , methodId- , eventId- , SolidityType(..)- , parseSolidityType- ) where--import Control.Monad (void)-import Crypto.Hash (Digest, Keccak_256, hash)-import Data.Aeson (FromJSON (parseJSON), Options (constructorTagModifier, fieldLabelModifier, sumEncoding),- SumEncoding (TaggedObject),- ToJSON (toJSON), defaultOptions)-import Data.Aeson.TH (deriveJSON)-import Data.Monoid ((<>))-import Data.Text (Text)-import qualified Data.Text as T (dropEnd, pack, take, unlines, unpack)-import Data.Text.Encoding (encodeUtf8)-import Text.Parsec (ParseError, char, choice, digit, eof,- lookAhead, many1, manyTill, optionMaybe,- parse, string, try, (<|>))-import Text.Parsec.Text (Parser)--import Data.String.Extra (toLowerFirst)---- | Method argument-data FunctionArg = FunctionArg- { funArgName :: Text- -- ^ Argument name- , funArgType :: Text- -- ^ Argument type- } deriving (Show, Eq, Ord)--$(deriveJSON- (defaultOptions {fieldLabelModifier = toLowerFirst . drop 6})- ''FunctionArg)---- | Event argument-data EventArg = EventArg- { eveArgName :: Text- -- ^ Argument name- , eveArgType :: Text- -- ^ Argument type- , eveArgIndexed :: Bool- -- ^ Argument is indexed (e.g. placed on topics of event)- } deriving (Show, Eq, Ord)--$(deriveJSON- (defaultOptions {fieldLabelModifier = toLowerFirst . drop 6})- ''EventArg)---- | Elementrary contract interface item-data Declaration- = DConstructor { conInputs :: [FunctionArg] }- -- ^ Contract constructor- | DFunction { funName :: Text- , funConstant :: Bool- , funInputs :: [FunctionArg]- , funOutputs :: Maybe [FunctionArg] }- -- ^ Method- | DEvent { eveName :: Text- , eveInputs :: [EventArg]- , eveAnonymous :: Bool }- -- ^ Event- | DFallback { falPayable :: Bool }- -- ^ Fallback function- deriving Show--instance Eq Declaration where- (DConstructor a) == (DConstructor b) = length a == length b- (DFunction a _ _ _) == (DFunction b _ _ _) = a == b- (DEvent a _ _) == (DEvent b _ _) = a == b- (DFallback _) == (DFallback _) = True- (==) _ _ = False--instance Ord Declaration where- compare (DConstructor a) (DConstructor b) = compare (length a) (length b)- compare (DFunction a _ _ _) (DFunction b _ _ _) = compare a b- compare (DEvent a _ _) (DEvent b _ _) = compare a b- compare (DFallback _) (DFallback _) = EQ-- compare DConstructor {} DFunction {} = LT- compare DConstructor {} DEvent {} = LT- compare DConstructor {} DFallback {} = LT-- compare DFunction {} DConstructor {} = GT- compare DFunction {} DEvent {} = LT- compare DFunction {} DFallback {} = LT-- compare DEvent {} DConstructor {} = GT- compare DEvent {} DFunction {} = GT- compare DEvent {} DFallback {} = LT-- compare DFallback {} DConstructor {} = GT- compare DFallback {} DFunction {} = GT- compare DFallback {} DEvent {} = GT--$(deriveJSON (defaultOptions {- sumEncoding = TaggedObject "type" "contents"- , constructorTagModifier = toLowerFirst . drop 1- , fieldLabelModifier = toLowerFirst . drop 3 })- ''Declaration)---- | Contract ABI is a list of method / event declarations-newtype ContractABI = ContractABI { unABI :: [Declaration] }- deriving (Eq, Ord)--instance FromJSON ContractABI where- parseJSON = fmap ContractABI . parseJSON--instance ToJSON ContractABI where- toJSON = toJSON . unABI--instance Show ContractABI where- show (ContractABI c) = T.unpack $ T.unlines $- [ "Contract:" ]- ++ foldMap showConstructor c ++- [ "\tEvents:" ]- ++ foldMap showEvent c ++- [ "\tMethods:" ]- ++ foldMap showMethod c--showConstructor :: Declaration -> [Text]-showConstructor x = case x of- DConstructor{} -> ["\tConstructor " <> signature x]- _ -> []--showEvent :: Declaration -> [Text]-showEvent x = case x of- DEvent{} -> ["\t\t" <> signature x]- _ -> []--showMethod :: Declaration -> [Text]-showMethod x = case x of- DFunction{} ->- ["\t\t" <> methodId x <> " " <> signature x]- _ -> []---- | Take a signature by given decl, e.g. foo(uint,string)-signature :: Declaration -> Text--signature (DConstructor inputs) = "(" <> args inputs <> ")"- where- args :: [FunctionArg] -> Text- args = T.dropEnd 1 . foldMap (<> ",") . fmap funArgType--signature (DFallback _) = "()"--signature (DFunction name _ inputs _) = name <> "(" <> args inputs <> ")"- where- args :: [FunctionArg] -> Text- args = T.dropEnd 1 . foldMap (<> ",") . fmap funArgType--signature (DEvent name inputs _) = name <> "(" <> args inputs <> ")"- where- args :: [EventArg] -> Text- args = T.dropEnd 1 . foldMap (<> ",") . fmap eveArgType---- | Localy compute Keccak-256 hash of given text-sha3 :: Text -> Text-{-# INLINE sha3 #-}-sha3 x = T.pack (show digest)- where digest :: Digest Keccak_256- digest = hash (encodeUtf8 x)---- | Generate method selector by given method 'Delcaration'-methodId :: Declaration -> Text-{-# INLINE methodId #-}-methodId = ("0x" <>) . T.take 8 . sha3 . signature---- | Generate event `topic0` hash by givent event 'Delcaration'-eventId :: Declaration -> Text-{-# INLINE eventId #-}-eventId = ("0x" <>) . sha3 . signature---- | Solidity types and parsers-data SolidityType =- SolidityBool- | SolidityAddress- | SolidityUint Int- | SolidityInt Int- | SolidityString- | SolidityBytesN Int- | SolidityBytes- | SolidityVector [Int] SolidityType- | SolidityArray SolidityType- deriving (Eq, Show)--numberParser :: Parser Int-numberParser = read <$> many1 digit--parseUint :: Parser SolidityType-parseUint = do- _ <- string "uint"- n <- numberParser- pure $ SolidityUint n--parseInt :: Parser SolidityType-parseInt = do- _ <- string "int"- n <- numberParser- pure $ SolidityInt n--parseBool :: Parser SolidityType-parseBool = string "bool" >> pure SolidityBool--parseString :: Parser SolidityType-parseString = string "string" >> pure SolidityString--parseBytes :: Parser SolidityType-parseBytes = do- _ <- string "bytes"- mn <- optionMaybe numberParser- pure $ maybe SolidityBytes SolidityBytesN mn--parseAddress :: Parser SolidityType-parseAddress = string "address" >> pure SolidityAddress--solidityBasicTypeParser :: Parser SolidityType-solidityBasicTypeParser =- choice [ try parseUint- , try parseInt- , try parseAddress- , try parseBool- , try parseString- , parseBytes- ]--parseVector :: Parser SolidityType-parseVector = do- s <- solidityBasicTypeParser- ns <- many1Till lengthParser ((lookAhead $ void (string "[]")) <|> eof)- pure $ SolidityVector ns s- where- many1Till :: Parser Int -> Parser () -> Parser [Int]- many1Till p end = do- a <- p- as <- manyTill p end- return (a : as)-- lengthParser = do- _ <- char '['- n <- numberParser- _ <- char ']'- pure n--parseArray :: Parser SolidityType-parseArray = do- s <- (try $ parseVector <* string "[]") <|> (solidityBasicTypeParser <* string "[]")- pure $ SolidityArray s---solidityTypeParser :: Parser SolidityType-solidityTypeParser =- choice [ try parseArray- , try parseVector- , solidityBasicTypeParser- ]--parseSolidityType :: Text -> Either ParseError SolidityType-parseSolidityType = parse solidityTypeParser "Solidity"
− src/Network/Ethereum/ABI/Prim.hs
@@ -1,30 +0,0 @@--- |--- Module : Network.Ethereum.ABI.Prim--- Copyright : Alexander Krupenkin 2016-2018--- License : BSD3------ Maintainer : mail@akru.me--- Stability : experimental--- Portability : noportable------ Ethereum ABI encoding primitive types.-----module Network.Ethereum.ABI.Prim (- Address- , Bytes- , BytesN- , IntN- , UIntN- , ListN- , Singleton(..)- ) where--import Network.Ethereum.ABI.Prim.Address (Address)-import Network.Ethereum.ABI.Prim.Bool ()-import Network.Ethereum.ABI.Prim.Bytes (Bytes, BytesN)-import Network.Ethereum.ABI.Prim.Int (IntN, UIntN)-import Network.Ethereum.ABI.Prim.List (ListN)-import Network.Ethereum.ABI.Prim.String ()-import Network.Ethereum.ABI.Prim.Tagged ()-import Network.Ethereum.ABI.Prim.Tuple (Singleton (..))
− src/Network/Ethereum/ABI/Prim/Address.hs
@@ -1,81 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE OverloadedStrings #-}---- |--- Module : Network.Ethereum.ABI.Prim.Address--- Copyright : Alexander Krupenkin 2016-2018--- License : BSD3------ Maintainer : mail@akru.me--- Stability : experimental--- Portability : noportable------ Ethereum ABI address type.-----module Network.Ethereum.ABI.Prim.Address (- Address- ) where--import Control.Monad ((<=<))-import Data.Aeson (FromJSON (..), ToJSON (..),- Value (String))-import Data.ByteArray (Bytes, zero)-import Data.ByteArray.Encoding (Base (Base16), convertFromBase,- convertToBase)-import Data.ByteString (ByteString)-import qualified Data.ByteString.Char8 as C8 (drop, pack, take, unpack)-import Data.Monoid ((<>))-import Data.String (IsString (..))-import Data.Text.Encoding (decodeUtf8, encodeUtf8)-import Generics.SOP (Generic)-import qualified GHC.Generics as GHC (Generic)--import Network.Ethereum.ABI.Class (ABIGet (..), ABIPut (..),- ABIType (..))-import Network.Ethereum.ABI.Codec (decode, encode)-import Network.Ethereum.ABI.Prim.Int (UIntN)---- | Ethereum account address-newtype Address = Address { unAddress :: UIntN 160 }- deriving (Eq, Ord, GHC.Generic)--instance Generic Address---- TODO: Address . drop 12 . sha3-{--fromPublic :: ByteArrayAccess bin => bin -> Maybe Address-fromPublic = undefined--}--fromHexString :: ByteString -> Either String Address-fromHexString = decode . align <=< convertFromBase Base16 . trim0x- where trim0x s | C8.take 2 s == "0x" = C8.drop 2 s- | otherwise = s- align = (zero 12 <>) :: Bytes -> Bytes--toHexString :: Address -> ByteString-toHexString = ("0x" <>) . convertToBase Base16 . C8.drop 12 . encode--instance Show Address where- show = C8.unpack . toHexString--instance IsString Address where- fromString = either error id . fromHexString . C8.pack--instance ABIType Address where- isDynamic _ = False--instance ABIGet Address where- abiGet = Address <$> abiGet--instance ABIPut Address where- abiPut = abiPut . unAddress--instance FromJSON Address where- parseJSON (String a) = either fail return $ fromHexString (encodeUtf8 a)- parseJSON _ = fail "Address should be a string"--instance ToJSON Address where- toJSON = String . decodeUtf8 . toHexString
− src/Network/Ethereum/ABI/Prim/Bool.hs
@@ -1,29 +0,0 @@-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}---- |--- Module : Network.Ethereum.ABI.Prim.Bool--- Copyright : Alexander Krupenkin 2016-2018--- License : BSD3------ Maintainer : mail@akru.me--- Stability : experimental--- Portability : noportable------ Ethereum ABI boolean type.-----module Network.Ethereum.ABI.Prim.Bool () where--import Network.Ethereum.ABI.Class (ABIGet (..), ABIPut (..),- ABIType (..))-import Network.Ethereum.ABI.Prim.Int (getWord256, putWord256)--instance ABIType Bool where- isDynamic _ = False--instance ABIGet Bool where- abiGet = toEnum . fromIntegral <$> getWord256--instance ABIPut Bool where- abiPut = putWord256 . fromIntegral . fromEnum
− src/Network/Ethereum/ABI/Prim/Bytes.hs
@@ -1,118 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-}---- |--- Module : Network.Ethereum.ABI.Prim.Bytes--- Copyright : Alexander Krupenkin 2016-2018--- License : BSD3------ Maintainer : mail@akru.me--- Stability : experimental--- Portability : noportable------ Ethereum ABI bytes and bytesN types.-----module Network.Ethereum.ABI.Prim.Bytes (- Bytes- , BytesN- ) where--import Data.Aeson (FromJSON (..), ToJSON (..),- Value (String))-import Data.ByteArray (Bytes, convert, length, zero)-import Data.ByteArray.Encoding (Base (Base16), convertFromBase,- convertToBase)-import Data.ByteArray.Sized (SizedByteArray,- unSizedByteArray,- unsafeFromByteArrayAccess)-import qualified Data.ByteArray.Sized as S (take)-import Data.ByteString (ByteString)-import qualified Data.ByteString.Char8 as C8-import Data.Monoid ((<>))-import Data.Proxy (Proxy (..))-import Data.Serialize (Get, Putter, getBytes,- putByteString)-import Data.String (IsString (..))-import qualified Data.Text as T (append, drop, take)-import Data.Text.Encoding (decodeUtf8, encodeUtf8)-import GHC.TypeLits-import Prelude hiding (length)--import Network.Ethereum.ABI.Class (ABIGet (..), ABIPut (..),- ABIType (..))-import Network.Ethereum.ABI.Prim.Int (getWord256, putWord256)--instance ABIType ByteString where- isDynamic _ = True--instance ABIGet ByteString where- abiGet = abiGetByteString--instance ABIPut ByteString where- abiPut = abiPutByteString--instance ABIType Bytes where- isDynamic _ = True--instance ABIGet Bytes where- abiGet = convert <$> abiGetByteString--instance ABIPut Bytes where- abiPut = abiPutByteString . convert--instance IsString Bytes where- fromString ('0' : 'x' : hex) = either error id $ convertFromBase Base16 (C8.pack hex)- fromString str = convert (C8.pack str)--instance FromJSON Bytes where- parseJSON (String hex)- | T.take 2 hex == "0x" =- either fail pure $ convertFromBase Base16 $ encodeUtf8 $ T.drop 2 hex- | otherwise = fail "Hex string should have '0x' prefix"- parseJSON _ = fail "Bytes should be encoded as hex string"--instance ToJSON Bytes where- toJSON = toJSON . T.append "0x" . decodeUtf8 . convertToBase Base16--type BytesN n = SizedByteArray n Bytes--instance (n <= 32) => ABIType (BytesN n) where- isDynamic _ = False--instance (KnownNat n, n <= 32) => ABIGet (BytesN n) where- abiGet = do- ba <- unsafeFromByteArrayAccess <$> getBytes 32- return $ S.take (ba :: BytesN 32)--instance (KnownNat n, n <= 32) => ABIPut (BytesN n) where- abiPut ba = putByteString $ convert ba <> zero (32 - len)- where len = fromIntegral $ natVal (Proxy :: Proxy n)--instance (KnownNat n, n <= 32) => IsString (BytesN n) where- fromString = unsafeFromByteArrayAccess . (fromString :: String -> Bytes)--instance (KnownNat n, n <= 32) => FromJSON (BytesN n) where- parseJSON v = do ba <- parseJSON v- return $ unsafeFromByteArrayAccess (ba :: Bytes)--instance (KnownNat n, n <= 32) => ToJSON (BytesN n) where- toJSON ba = toJSON (unSizedByteArray ba :: Bytes)--abiGetByteString :: Get ByteString-abiGetByteString = do- len <- fromIntegral <$> getWord256- ba <- getBytes len- _ <- getBytes $ 32 - len `mod` 32- return ba--abiPutByteString :: Putter ByteString-abiPutByteString bs = do- putWord256 $ fromIntegral len- putByteString $ bs <> zero (32 - len `mod` 32)- where len = length bs
− src/Network/Ethereum/ABI/Prim/Int.hs
@@ -1,119 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-}---- |--- Module : Network.Ethereum.Encoding.Prim.Int--- Copyright : Alexander Krupenkin 2016-2018--- License : BSD3------ Maintainer : mail@akru.me--- Stability : experimental--- Portability : noportable------ Ethereum ABI intN and uintN types.-----module Network.Ethereum.ABI.Prim.Int (- IntN- , UIntN- , getWord256- , putWord256- ) where--import qualified Basement.Numerical.Number as Basement (toInteger)-import Basement.Types.Word256 (Word256 (Word256))-import qualified Basement.Types.Word256 as Basement (quot, rem)-import Data.Bits (Bits (testBit))-import Data.Proxy (Proxy (..))-import Data.Serialize (Get, Putter, Serialize (get, put))-import GHC.Generics (Generic)-import GHC.TypeLits--import Network.Ethereum.ABI.Class (ABIGet (..), ABIPut (..),- ABIType (..))--instance Real Word256 where- toRational = toRational . toInteger--instance Integral Word256 where- toInteger = Basement.toInteger- quotRem a b = (Basement.quot a b, Basement.rem a b)--newtype UIntN (n :: Nat) = UIntN { unUIntN :: Word256 }- deriving (Eq, Ord, Enum, Num, Bits, Generic)--instance (KnownNat n, n <= 256) => Show (UIntN n) where- show = show . unUIntN--instance (KnownNat n, n <= 256) => Bounded (UIntN n) where- minBound = 0- maxBound = 2 ^ (natVal (Proxy :: Proxy n)) - 1--instance (KnownNat n, n <= 256) => Real (UIntN n) where- toRational = toRational . toInteger--instance (KnownNat n, n <= 256) => Integral (UIntN n) where- toInteger = toInteger . unUIntN- quotRem (UIntN a) (UIntN b) = (UIntN $ quot a b, UIntN $ rem a b)--instance (n <= 256) => ABIType (UIntN n) where- isDynamic _ = False--instance (n <= 256) => ABIGet (UIntN n) where- abiGet = UIntN <$> getWord256--instance (n <= 256) => ABIPut (UIntN n) where- abiPut = putWord256 . unUIntN---- TODO: Signed data type-newtype IntN (n :: Nat) = IntN { unIntN :: Word256 }- deriving (Eq, Ord, Enum, Bits, Generic)--instance (KnownNat n, n <= 256) => Show (IntN n) where- show = show . toInteger--instance (KnownNat n, n <= 256) => Bounded (IntN n) where- minBound = negate $ 2 ^ (natVal (Proxy :: Proxy (n :: Nat)) - 1)- maxBound = 2 ^ (natVal (Proxy :: Proxy (n :: Nat)) - 1) - 1--instance (KnownNat n, n <= 256) => Num (IntN n) where- a + b = fromInteger (toInteger a + toInteger b)- a - b = fromInteger (toInteger a - toInteger b)- a * b = fromInteger (toInteger a * toInteger b)- abs = fromInteger . abs . toInteger- negate = fromInteger . negate . toInteger- signum = fromInteger . signum . toInteger- fromInteger x- | x >= 0 = IntN (fromInteger x)- | otherwise = IntN (fromInteger $ 2 ^ 256 + x)--instance (KnownNat n, n <= 256) => Real (IntN n) where- toRational = toRational . toInteger--instance (KnownNat n, n <= 256) => Integral (IntN n) where- quotRem (IntN a) (IntN b) = (IntN $ quot a b, IntN $ rem a b)- toInteger x- | testBit x 255 = toInteger (unIntN x) - 2 ^ 256- | otherwise = toInteger $ unIntN x--instance (n <= 256) => ABIType (IntN n) where- isDynamic _ = False--instance (n <= 256) => ABIGet (IntN n) where- abiGet = IntN <$> getWord256--instance (n <= 256) => ABIPut (IntN n) where- abiPut = putWord256 . unIntN--putWord256 :: Putter Word256-putWord256 (Word256 a3 a2 a1 a0) =- put a3 >> put a2 >> put a1 >> put a0--getWord256 :: Get Word256-getWord256 = Word256 <$> get <*> get <*> get <*> get
− src/Network/Ethereum/ABI/Prim/List.hs
@@ -1,55 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE UndecidableInstances #-}---- |--- Module : Network.Ethereum.ABI.Prim.List--- Copyright : Alexander Krupenkin 2016-2018--- License : BSD3------ Maintainer : mail@akru.me--- Stability : experimental--- Portability : noportable------ Ethereum ABI dynamic and static size vectors based on linked lists.-----module Network.Ethereum.ABI.Prim.List (- ListN- ) where--import Basement.Nat (NatWithinBound)-import Basement.Sized.List (ListN, toListN_, unListN)-import qualified Basement.Sized.List as SL (mapM_, replicateM)-import Control.Monad (replicateM)-import GHC.Exts (IsList (..))-import GHC.TypeLits (KnownNat)--import Network.Ethereum.ABI.Class (ABIGet (..), ABIPut (..),- ABIType (..))-import Network.Ethereum.ABI.Prim.Int (getWord256, putWord256)--instance ABIType [a] where- isDynamic _ = True--instance ABIPut a => ABIPut [a] where- abiPut l = do putWord256 $ fromIntegral (length l)- foldMap abiPut l--instance ABIGet a => ABIGet [a] where- abiGet = do len <- fromIntegral <$> getWord256- replicateM len abiGet--instance ABIType (ListN n a) where- isDynamic _ = False--instance ABIPut a => ABIPut (ListN n a) where- abiPut = SL.mapM_ abiPut--instance (NatWithinBound Int n, KnownNat n, ABIGet a) => ABIGet (ListN n a) where- abiGet = SL.replicateM abiGet--instance (NatWithinBound Int n, KnownNat n) => IsList (ListN n a) where- type Item (ListN n a) = a- fromList = toListN_- toList = unListN
− src/Network/Ethereum/ABI/Prim/String.hs
@@ -1,29 +0,0 @@--- |--- Module : Network.Ethereum.ABI.Prim.String--- Copyright : Alexander Krupenkin 2016-2018--- License : BSD3------ Maintainer : mail@akru.me--- Stability : experimental--- Portability : noportable------ Ethereum ABI UTF8-encoded string type.-----module Network.Ethereum.ABI.Prim.String () where--import Data.Text (Text)-import Data.Text.Encoding (decodeUtf8, encodeUtf8)--import Network.Ethereum.ABI.Class (ABIGet (..), ABIPut (..),- ABIType (..))-import Network.Ethereum.ABI.Prim.Bytes ()--instance ABIType Text where- isDynamic _ = True--instance ABIPut Text where- abiPut = abiPut . encodeUtf8--instance ABIGet Text where- abiGet = decodeUtf8 <$> abiGet
− src/Network/Ethereum/ABI/Prim/Tagged.hs
@@ -1,36 +0,0 @@-{-# LANGUAGE PolyKinds #-}-{-# LANGUAGE ScopedTypeVariables #-}---- |--- Module : Network.Ethereum.ABI.Prim.Tagged--- Copyright : Alexander Krupenkin 2016-2018--- License : BSD3------ Maintainer : mail@akru.me--- Stability : experimental--- Portability : noportable------ Ethereum ABI UTF8-encoded tagged types.-----module Network.Ethereum.ABI.Prim.Tagged (- Tagged- ) where--import Data.Proxy (Proxy (..))-import Data.Tagged (Tagged (..))-import Generics.SOP (Generic)--import Network.Ethereum.ABI.Class (ABIGet (..), ABIPut (..),- ABIType (..))--instance ABIType a => ABIType (Tagged t a) where- isDynamic _ = isDynamic (Proxy :: Proxy a)--instance ABIPut a => ABIPut (Tagged t a) where- abiPut (Tagged a) = abiPut a--instance ABIGet a => ABIGet (Tagged t a) where- abiGet = Tagged <$> abiGet--instance Generic a => Generic (Tagged t a)
− src/Network/Ethereum/ABI/Prim/Tuple.hs
@@ -1,45 +0,0 @@-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# LANGUAGE TemplateHaskell #-}---- |--- Module : Network.Ethereum.ABI.Prim.Tuple--- Copyright : Alexander Krupenkin 2016-2018--- License : BSD3------ Maintainer : mail@akru.me--- Stability : experimental--- Portability : noportable------ Tuple type abi encoding instances.-----module Network.Ethereum.ABI.Prim.Tuple (- Singleton(..)- ) where--import Data.Proxy (Proxy (..))-import Generics.SOP (Generic)-import qualified GHC.Generics as GHC (Generic)--import Network.Ethereum.ABI.Class (ABIGet, ABIPut,- ABIType (..))-import Network.Ethereum.ABI.Generic ()-import Network.Ethereum.ABI.Prim.Tuple.TH (tupleDecs)---- | The type for one-tuples-newtype Singleton a = Singleton { unSingleton :: a }- deriving GHC.Generic--deriving instance Eq a => Eq (Singleton a)-deriving instance Show a => Show (Singleton a)-instance Generic (Singleton a)--instance ABIType a => ABIType (Singleton a) where- isDynamic _ = isDynamic (Proxy :: Proxy a)--instance ABIGet a => ABIGet (Singleton a)-instance ABIPut a => ABIPut (Singleton a)--$(fmap concat $ sequence $ map tupleDecs [2..20])
− src/Network/Ethereum/ABI/Prim/Tuple/TH.hs
@@ -1,34 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}---- |--- Module : Network.Ethereum.ABI.Prim.Tuple.TH--- Copyright : Alexander Krupenkin 2016-2018--- License : BSD3------ Maintainer : mail@akru.me--- Stability : experimental--- Portability : noportable------ This module is for internal usage only.--- It contains tuple abi encoding template haskell generator.-----module Network.Ethereum.ABI.Prim.Tuple.TH (tupleDecs) where---import Control.Monad (replicateM)-import Language.Haskell.TH (DecsQ, Type (VarT), appT, clause,- conT, cxt, funD, instanceD,- newName, normalB, tupleT)--import Network.Ethereum.ABI.Class (ABIGet, ABIPut, ABIType (..))--tupleDecs :: Int -> DecsQ-tupleDecs n = do- vars <- replicateM n $ newName "a"- let types = fmap (pure . VarT) vars- sequence $- [ instanceD (cxt $ map (appT $ conT ''ABIType) types) (appT (conT ''ABIType) (foldl appT (tupleT n) types))- [funD 'isDynamic [clause [] (normalB [|const False|]) []]]- , instanceD (cxt $ map (appT $ conT ''ABIGet) types) (appT (conT ''ABIGet) (foldl appT (tupleT n) types)) []- , instanceD (cxt $ map (appT $ conT ''ABIPut) types) (appT (conT ''ABIPut) (foldl appT (tupleT n) types)) [] ]
+ src/Network/Ethereum/Account.hs view
@@ -0,0 +1,54 @@+-- |+-- Module : Network.Ethereum.Account+-- Copyright : Alexander Krupenkin 2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : unportable+--+-- In Etereun there are two types of accounts:+-- * Externally owned account (EOAs): an account controlled by a private key, and if you own the private key associated with the EOA you have the ability to send ether and messages from it.+-- * Contract: an account that has its own code, and is controlled by code.+--+-- This module exports different kinds of EOAs: default, node managed and local. Node managed accounts+-- use 'Personal' JSON-RPC API for signing transactions. Local account sign transaction locally and+-- use 'sendRawTransaction' method to export transaction to Ethereum network.+--++module Network.Ethereum.Account+ (+ -- * The @Account@ type+ Account(..)++ -- * Default node account+ , DefaultAccount++ -- * Unlockable node account+ , PersonalAccount+ , Personal(..)++ -- * Local key account+ , PrivateKeyAccount+ , PrivateKey(..)++ -- * Transaction paramitrization function and lenses+ , withParam+ , to+ , value+ , gasLimit+ , gasPrice+ , block+ , account++ ) where++import Network.Ethereum.Account.Class (Account (..))+import Network.Ethereum.Account.Default (DefaultAccount)+import Network.Ethereum.Account.Internal (account, block, gasLimit,+ gasPrice, to, value,+ withParam)+import Network.Ethereum.Account.Personal (Personal (..),+ PersonalAccount)+import Network.Ethereum.Account.PrivateKey (PrivateKey (..),+ PrivateKeyAccount)
+ src/Network/Ethereum/Account/Class.hs view
@@ -0,0 +1,56 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE MultiParamTypeClasses #-}++-- |+-- Module : Network.Ethereum.Account.Class+-- Copyright : Alexander Krupenkin 2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : unportable+--+-- Ethereum external owned account abstraction.+--++module Network.Ethereum.Account.Class where++import Control.Monad.Trans (MonadTrans)++import Data.Solidity.Abi (AbiGet)+import Network.Ethereum.Api.Types (TxReceipt)+import Network.Ethereum.Contract.Method (Method)+import Network.JsonRpc.TinyClient (JsonRpc)++-- | Account is needed for sending transactions to blockchain+--+-- Typically account is provided by node. In this case node manage accounts:+-- encrypt and decrypt private keys, manipulate files etc. In other case web3+-- can derive account from private key and send to node already signed transactions.+--+class MonadTrans t => Account a t | t -> a where++ -- | Run computation with given account credentials+ withAccount :: JsonRpc m+ => a+ -- ^ Account params (like a password or private key)+ -> t m b+ -- ^ Computation that use account for sending transactions+ -> m b+ -- ^ Json-rpc monad++ -- | Send transaction to contract, like a 'write' command+ send :: (JsonRpc m, Method args)+ => args+ -- ^ Contract method arguments+ -> t m TxReceipt+ -- ^ Receipt of sended transaction++ -- | Call constant method of contract, like a 'read' command+ call :: (JsonRpc m, Method args, AbiGet result)+ => args+ -- ^ Contact method arguments+ -> t m result+ -- ^ Decoded result of method call+
+ src/Network/Ethereum/Account/Default.hs view
@@ -0,0 +1,72 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeSynonymInstances #-}++-- |+-- Module : Network.Ethereum.Account.Default+-- Copyright : Alexander Krupenkin 2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : unportable+--+-- Default node managed account (typically the first of accounts list).+--++module Network.Ethereum.Account.Default where++import Control.Monad.Catch (throwM)+import Control.Monad.State.Strict (get, runStateT)+import Control.Monad.Trans (MonadTrans (..))+import qualified Data.ByteArray as BA (convert)+import Data.Maybe (listToMaybe)+import Data.Monoid ((<>))+import Data.Proxy (Proxy (..))++import Data.Solidity.Abi.Codec (decode, encode)+import Network.Ethereum.Account.Class (Account (..))+import Network.Ethereum.Account.Internal (AccountT (..),+ CallParam (..),+ defaultCallParam, getCall,+ getReceipt)+import qualified Network.Ethereum.Api.Eth as Eth (accounts, call,+ estimateGas,+ sendTransaction)+import Network.Ethereum.Api.Provider (Web3Error (ParserFail))+import Network.Ethereum.Api.Types (Call (callData, callFrom, callGas))+import Network.Ethereum.Contract.Method (Method (..))++type DefaultAccount = AccountT ()++instance Account () DefaultAccount where+ withAccount _ =+ fmap fst . flip runStateT (defaultCallParam ()) . runAccountT++ send (args :: a) = do+ c <- getCall+ lift $ do+ accounts <- Eth.accounts+ let dat = selector (Proxy :: Proxy a) <> encode args+ params = c { callData = Just $ BA.convert dat+ , callFrom = listToMaybe accounts }++ gasLimit <- Eth.estimateGas params+ let params' = params { callGas = Just gasLimit }++ getReceipt =<< Eth.sendTransaction params'++ call (args :: a) = do+ c <- getCall+ CallParam{..} <- get+ res <- lift $ do+ accounts <- Eth.accounts+ let dat = selector (Proxy :: Proxy a) <> encode args+ params = c { callData = Just $ BA.convert dat+ , callFrom = listToMaybe accounts }+ Eth.call params _block+ case decode res of+ Right r -> return r+ Left e -> lift $ throwM (ParserFail e)
+ src/Network/Ethereum/Account/Internal.hs view
@@ -0,0 +1,130 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RecordWildCards #-}++-- |+-- Module : Network.Ethereum.Account.Internal+-- Copyright : Alexander Krupenkin 2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : unportable+--+-- Internal types and functions of 'Account' module.+--++module Network.Ethereum.Account.Internal where++import Control.Concurrent (threadDelay)+import Control.Monad.IO.Class (liftIO)+import Control.Monad.State.Strict (MonadState (..), StateT (..),+ withStateT)+import Control.Monad.Trans (MonadTrans (..))+import Data.Default (Default (..))+import Data.Maybe (fromMaybe)+import Lens.Micro (Lens', lens)++import Data.ByteArray.HexString (HexString)+import Data.Solidity.Prim (Address)+import Network.Ethereum.Account.Class (Account)+import qualified Network.Ethereum.Api.Eth as Eth (getTransactionReceipt)+import Network.Ethereum.Api.Types (Call (..),+ DefaultBlock (Latest),+ TxReceipt (receiptTransactionHash))+import Network.Ethereum.Unit (Unit (..))+import Network.JsonRpc.TinyClient (JsonRpc)++-- | Account is needed to send transactions to blockchain++-- | Transaction parametrization data type+data CallParam p = CallParam+ { _to :: Maybe Address+ -- ^ Transaction recepient+ , _value :: Integer+ -- ^ Transaction value+ , _gasLimit :: Maybe Integer+ -- ^ Transaction gas limit+ , _gasPrice :: Maybe Integer+ -- ^ Transaction gas price+ , _block :: DefaultBlock+ -- ^ Call block number+ , _account :: p+ -- ^ Account params to sign transaction+ } deriving Eq++-- | Transaction recipient lens+to :: Lens' (CallParam p) Address+to = lens (fromMaybe def . _to) $ \a b -> a { _to = Just b }++-- | Transaction value lens+value :: Unit value => Lens' (CallParam p) value+value = lens (fromWei . _value) $ \a b -> a { _value = toWei b }++-- | Transaction gas limit lens+gasLimit :: Lens' (CallParam p) (Maybe Integer)+gasLimit = lens _gasLimit $ \a b -> a { _gasLimit = b }++-- | Transaction gas price lens+gasPrice :: Unit gasprice => Lens' (CallParam p) (Maybe gasprice)+gasPrice = lens (fmap fromWei . _gasPrice) $ \a b -> a { _gasPrice = toWei <$> b }++-- | Call execution block lens+block :: Lens' (CallParam p) DefaultBlock+block = lens _block $ \a b -> a { _block = b }++-- | EOA params lens+account :: Lens' (CallParam p) p+account = lens _account $ \a b -> a { _account = b }++-- | Monad transformer for sending parametrized transactions from account+newtype AccountT p m a = AccountT+ { runAccountT :: StateT (CallParam p) m a }+ deriving (Functor, Applicative, Monad, MonadTrans)++instance Monad m => MonadState (CallParam p) (AccountT p m) where+ get = AccountT get+ put = AccountT . put++-- | @withParam@ is very similar to @withStateT@ function, it's used+-- to set parameters of transaction locally and revert params after out of scope.+--+-- @+-- withAccount () $+-- withParam (to .~ tokenAddress) $+-- transfer alice 42+-- @+withParam :: Account p (AccountT p)+ => (CallParam p -> CallParam p)+ -> AccountT p m a+ -> AccountT p m a+{-# INLINE withParam #-}+withParam f m = AccountT $ withStateT f $ runAccountT m++defaultCallParam :: a -> CallParam a+{-# INLINE defaultCallParam #-}+defaultCallParam = CallParam def 0 Nothing Nothing Latest++getCall :: MonadState (CallParam p) m => m Call+getCall = do+ CallParam{..} <- get+ return $ def { callTo = _to+ , callValue = Just $ fromInteger _value+ , callGas = fromInteger <$> _gasLimit+ , callGasPrice = fromInteger <$> _gasPrice+ }++getReceipt :: JsonRpc m => HexString -> m TxReceipt+getReceipt tx = do+ mbreceipt <- Eth.getTransactionReceipt tx+ case mbreceipt of+ Just receipt -> return receipt+ Nothing -> do+ liftIO $ threadDelay 100000+ -- TODO: avoid inifinite loop+ getReceipt tx++updateReceipt :: JsonRpc m => TxReceipt -> m TxReceipt+{-# INLINE updateReceipt #-}+updateReceipt = getReceipt . receiptTransactionHash
+ src/Network/Ethereum/Account/Personal.hs view
@@ -0,0 +1,81 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeSynonymInstances #-}++-- |+-- Module : Network.Ethereum.Account.Personal+-- Copyright : Alexander Krupenkin 2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : unportable+--+-- Node managed unlockable account. Typically to send transaction from this account+-- password is required.+--++module Network.Ethereum.Account.Personal where++import Control.Monad.State.Strict (get, runStateT)+import Control.Monad.Trans (lift)+import qualified Data.ByteArray as BA (convert)+import Data.Default (Default (..))+import Data.Monoid ((<>))+import Data.Proxy (Proxy (..))++import Data.Solidity.Abi.Codec (decode, encode)+import Data.Solidity.Prim.Address (Address)+import Network.Ethereum.Account.Class (Account (..))+import Network.Ethereum.Account.Internal (AccountT (..),+ CallParam (..),+ defaultCallParam, getCall,+ getReceipt)+import qualified Network.Ethereum.Api.Eth as Eth (call, estimateGas)+import Network.Ethereum.Api.Personal (Passphrase)+import qualified Network.Ethereum.Api.Personal as Personal (sendTransaction)+import Network.Ethereum.Api.Types (Call (callData, callFrom, callGas))+import Network.Ethereum.Contract.Method (selector)++-- | Unlockable node managed account params+data Personal = Personal {+ personalAddress :: !Address+ , personalPassphrase :: !Passphrase+ } deriving (Eq, Show)++instance Default Personal where+ def = Personal def ""++type PersonalAccount = AccountT Personal++instance Account Personal PersonalAccount where+ withAccount a =+ fmap fst . flip runStateT (defaultCallParam a) . runAccountT++ send (args :: a) = do+ CallParam{..} <- get+ c <- getCall+ lift $ do+ let dat = selector (Proxy :: Proxy a) <> encode args+ params = c { callFrom = Just $ personalAddress _account+ , callData = Just $ BA.convert dat }++ gasLimit <- Eth.estimateGas params+ let params' = params { callGas = Just gasLimit }++ getReceipt =<< Personal.sendTransaction params' (personalPassphrase _account)++ call (args :: a) = do+ s <- get+ case s of+ CallParam _ _ _ _ block (Personal address _) -> do+ c <- getCall+ let dat = selector (Proxy :: Proxy a) <> encode args+ params = c { callFrom = Just address, callData = Just $ BA.convert dat }+ res <- lift $ Eth.call params block+ case decode res of+ Right r -> return r+ Left e -> fail e
+ src/Network/Ethereum/Account/PrivateKey.hs view
@@ -0,0 +1,127 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeSynonymInstances #-}++-- |+-- Module : Network.Ethereum.Account.PrivateKey+-- Copyright : Alexander Krupenkin 2018+-- Roy Blankman 2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : unportable+--++module Network.Ethereum.Account.PrivateKey where++import Control.Monad.State.Strict (get, runStateT)+import Control.Monad.Trans (lift)+import Crypto.Secp256k1 (CompactRecSig (..), SecKey,+ derivePubKey)+import Data.ByteArray (convert)+import Data.ByteString (ByteString)+import Data.ByteString.Short (fromShort)+import Data.Default (Default (..))+import Data.Maybe (fromJust, fromMaybe)+import Data.Monoid (mempty, (<>))+import Data.Proxy (Proxy (..))+import Data.RLP (packRLP, rlpEncode)++import Crypto.Ethereum (ecsign)+import Data.ByteArray.HexString (HexString, toBytes)+import Data.Solidity.Abi.Codec (decode, encode)+import Data.Solidity.Prim.Address (fromPubKey, toHexString)+import Network.Ethereum.Account.Class (Account (..))+import Network.Ethereum.Account.Internal (AccountT (..),+ CallParam (..),+ defaultCallParam, getCall,+ getReceipt)+import qualified Network.Ethereum.Api.Eth as Eth (call, estimateGas,+ getTransactionCount,+ sendRawTransaction)+import Network.Ethereum.Api.Types (Call (..), unQuantity)+import Network.Ethereum.Chain (foundation)+import Network.Ethereum.Contract.Method (selector)+import Network.Ethereum.Unit (Shannon, toWei)++-- | Local EOA params+data PrivateKey = PrivateKey+ { privateKey :: !SecKey+ , privateKeyChain :: !Integer+ } deriving (Eq, Show)++instance Default PrivateKey where+ def = PrivateKey "" foundation++type PrivateKeyAccount = AccountT PrivateKey++instance Account PrivateKey PrivateKeyAccount where+ withAccount a =+ fmap fst . flip runStateT (defaultCallParam a) . runAccountT++ send (args :: a) = do+ CallParam{..} <- get+ c <- getCall++ let dat = selector (Proxy :: Proxy a) <> encode args+ address = fromPubKey (derivePubKey $ privateKey _account)++ nonce <- lift $ Eth.getTransactionCount address _block+ let params = c { callFrom = Just address+ , callNonce = Just nonce+ , callData = Just $ convert dat }++ gasLimit <- lift $ Eth.estimateGas params+ let params' = params { callGas = Just gasLimit }++ let signed = signTransaction params' (privateKeyChain _account) (privateKey _account)+ lift $ getReceipt =<< Eth.sendRawTransaction signed++ call (args :: a) = do+ CallParam{..} <- get+ c <- getCall+ let dat = selector (Proxy :: Proxy a) <> encode args+ address = fromPubKey (derivePubKey $ privateKey _account)+ params = c { callFrom = Just address, callData = Just $ convert dat }++ res <- lift $ Eth.call params _block+ case decode res of+ Right r -> return r+ Left e -> fail e++encodeTransaction :: Call+ -> Either Integer (Integer, ByteString, ByteString)+ -> HexString+encodeTransaction Call{..} vrs = do+ let (to :: ByteString) = maybe mempty (toBytes . toHexString) callTo+ (value :: Integer) = unQuantity $ fromJust callValue+ (nonce :: Integer) = unQuantity $ fromJust callNonce+ (gasPrice :: Integer) = maybe defaultGasPrice unQuantity callGasPrice+ (gasLimit :: Integer) = unQuantity $ fromJust callGas+ (input :: ByteString) = convert $ fromMaybe mempty callData++ rlp $ case vrs of+ -- Unsigned transaction by EIP155+ Left chain_id -> (nonce, gasPrice, gasLimit, to, value, input, chain_id, mempty, mempty)+ -- Signed transaction+ Right (v, r, s) -> (nonce, gasPrice, gasLimit, to, value, input, v, s, r)+ where+ rlp = convert . packRLP . rlpEncode+ defaultGasPrice = toWei (5 :: Shannon)++signTransaction :: Call+ -> Integer+ -> SecKey+ -> HexString+signTransaction c i key = encodeTransaction c $ Right (v', r, s)+ where+ unsigned = encodeTransaction c (Left i)+ recSig = ecsign key unsigned+ v = fromIntegral $ getCompactRecSigV recSig+ r = fromShort $ getCompactRecSigR recSig+ s = fromShort $ getCompactRecSigS recSig+ v' = v + 35 + 2 * i -- Improved 'v' according to EIP155
+ src/Network/Ethereum/Account/Safe.hs view
@@ -0,0 +1,55 @@+{-# 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
+ src/Network/Ethereum/Api/Eth.hs view
@@ -0,0 +1,248 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}++-- |+-- Module : Network.Ethereum.Web3.Eth+-- Copyright : Alexander Krupenkin 2016-2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : unknown+--+-- Ethereum node JSON-RPC API methods with `eth_` prefix.+--++module Network.Ethereum.Api.Eth where++import Data.ByteArray.HexString (HexString)+import Data.Solidity.Prim.Address (Address)+import Data.Text (Text)+import Network.Ethereum.Api.Types (Block, Call, Change, DefaultBlock,+ Filter, Quantity, SyncingState,+ Transaction, TxReceipt)+import Network.JsonRpc.TinyClient (JsonRpc (..))++-- | Returns the current ethereum protocol version.+protocolVersion :: JsonRpc m => m Text+{-# INLINE protocolVersion #-}+protocolVersion = remote "eth_protocolVersion"++-- | Returns an object with data about the sync status or false.+syncing :: JsonRpc m => m SyncingState+{-# INLINE syncing #-}+syncing = remote "eth_syncing"++-- | Returns the client coinbase address.+coinbase :: JsonRpc m => m Address+{-# INLINE coinbase #-}+coinbase = remote "eth_coinbase"++-- | Returns true if client is actively mining new blocks.+mining :: JsonRpc m => m Bool+{-# INLINE mining #-}+mining = remote "eth_mining"++-- | Returns the number of hashes per second that the node is mining with.+hashrate :: JsonRpc m => m Quantity+{-# INLINE hashrate #-}+hashrate = remote "eth_hashrate"++-- | Returns the value from a storage position at a given address.+getStorageAt :: JsonRpc m => Address -> Quantity -> DefaultBlock -> m HexString+{-# INLINE getStorageAt #-}+getStorageAt = remote "eth_getStorageAt"++-- | Returns the number of transactions sent from an address.+getTransactionCount :: JsonRpc m => Address -> DefaultBlock -> m Quantity+{-# INLINE getTransactionCount #-}+getTransactionCount = remote "eth_getTransactionCount"++-- | Returns the number of transactions in a block from a block matching the given block hash.+getBlockTransactionCountByHash :: JsonRpc m => HexString -> m Quantity+{-# INLINE getBlockTransactionCountByHash #-}+getBlockTransactionCountByHash = remote "eth_getBlockTransactionCountByHash"++-- | Returns the number of transactions in a block matching the+-- given block number.+getBlockTransactionCountByNumber :: JsonRpc m => Quantity -> m Quantity+{-# INLINE getBlockTransactionCountByNumber #-}+getBlockTransactionCountByNumber = remote "eth_getBlockTransactionCountByNumber"++-- | Returns the number of uncles in a block from a block matching the given+-- block hash.+getUncleCountByBlockHash :: JsonRpc m => HexString -> m Quantity+{-# INLINE getUncleCountByBlockHash #-}+getUncleCountByBlockHash = remote "eth_getUncleCountByBlockHash"++-- | Returns the number of uncles in a block from a block matching the given+-- block number.+getUncleCountByBlockNumber :: JsonRpc m => Quantity -> m Quantity+{-# INLINE getUncleCountByBlockNumber #-}+getUncleCountByBlockNumber = remote "eth_getUncleCountByBlockNumber"++-- | Returns code at a given address.+getCode :: JsonRpc m => Address -> DefaultBlock -> m HexString+{-# INLINE getCode #-}+getCode = remote "eth_getCode"++-- | Returns an Ethereum specific signature with:+-- sign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))).+sign :: JsonRpc m => Address -> HexString -> m HexString+{-# INLINE sign #-}+sign = remote "eth_sign"++-- | Creates new message call transaction or a contract creation,+-- if the data field contains code.+sendTransaction :: JsonRpc m => Call -> m HexString+{-# INLINE sendTransaction #-}+sendTransaction = remote "eth_sendTransaction"++-- | Creates new message call transaction or a contract creation for signed+-- transactions.+sendRawTransaction :: JsonRpc m => HexString -> m HexString+{-# INLINE sendRawTransaction #-}+sendRawTransaction = remote "eth_sendRawTransaction"++-- | Returns the balance of the account of given address.+getBalance :: JsonRpc m => Address -> DefaultBlock -> m Quantity+{-# INLINE getBalance #-}+getBalance = remote "eth_getBalance"++-- | Creates a filter object, based on filter options, to notify when the+-- state changes (logs). To check if the state has changed, call+-- 'getFilterChanges'.+newFilter :: JsonRpc m => Filter e -> m Quantity+{-# INLINE newFilter #-}+newFilter = remote "eth_newFilter"++-- | Polling method for a filter, which returns an array of logs which+-- occurred since last poll.+getFilterChanges :: JsonRpc m => Quantity -> m [Change]+{-# INLINE getFilterChanges #-}+getFilterChanges = remote "eth_getFilterChanges"++-- | Uninstalls a filter with given id.+-- Should always be called when watch is no longer needed.+uninstallFilter :: JsonRpc m => Quantity -> m Bool+{-# INLINE uninstallFilter #-}+uninstallFilter = remote "eth_uninstallFilter"++-- | Returns an array of all logs matching a given filter object.+getLogs :: JsonRpc m => Filter e -> m [Change]+{-# INLINE getLogs #-}+getLogs = remote "eth_getLogs"++-- | Executes a new message call immediately without creating a+-- transaction on the block chain.+call :: JsonRpc m => Call -> DefaultBlock -> m HexString+{-# INLINE call #-}+call = remote "eth_call"++-- | Makes a call or transaction, which won't be added to the blockchain and+-- returns the used gas, which can be used for estimating the used gas.+estimateGas :: JsonRpc m => Call -> m Quantity+{-# INLINE estimateGas #-}+estimateGas = remote "eth_estimateGas"++-- | Returns information about a block by hash.+getBlockByHash :: JsonRpc m => HexString -> m Block+{-# INLINE getBlockByHash #-}+getBlockByHash = flip (remote "eth_getBlockByHash") True++-- | Returns information about a block by block number.+getBlockByNumber :: JsonRpc m => Quantity -> m Block+{-# INLINE getBlockByNumber #-}+getBlockByNumber = flip (remote "eth_getBlockByNumber") True++-- | Returns the information about a transaction requested by transaction hash.+getTransactionByHash :: JsonRpc m => HexString -> m (Maybe Transaction)+{-# INLINE getTransactionByHash #-}+getTransactionByHash = remote "eth_getTransactionByHash"++-- | Returns information about a transaction by block hash and transaction index position.+getTransactionByBlockHashAndIndex :: JsonRpc m => HexString -> Quantity -> m (Maybe Transaction)+{-# INLINE getTransactionByBlockHashAndIndex #-}+getTransactionByBlockHashAndIndex = remote "eth_getTransactionByBlockHashAndIndex"++-- | Returns information about a transaction by block number and transaction+-- index position.+getTransactionByBlockNumberAndIndex :: JsonRpc m => DefaultBlock -> Quantity -> m (Maybe Transaction)+{-# INLINE getTransactionByBlockNumberAndIndex #-}+getTransactionByBlockNumberAndIndex = remote "eth_getTransactionByBlockNumberAndIndex"++-- | Returns the receipt of a transaction by transaction hash.+getTransactionReceipt :: JsonRpc m => HexString -> m (Maybe TxReceipt)+{-# INLINE getTransactionReceipt #-}+getTransactionReceipt = remote "eth_getTransactionReceipt"++-- | Returns a list of addresses owned by client.+accounts :: JsonRpc m => m [Address]+{-# INLINE accounts #-}+accounts = remote "eth_accounts"++-- | Creates a filter in the node, to notify when a new block arrives.+newBlockFilter :: JsonRpc m => m Quantity+{-# INLINE newBlockFilter #-}+newBlockFilter = remote "eth_newBlockFilter"++-- | Polling method for a block filter, which returns an array of block hashes+-- occurred since last poll.+getBlockFilterChanges :: JsonRpc m => Quantity -> m [HexString]+{-# INLINE getBlockFilterChanges #-}+getBlockFilterChanges = remote "eth_getFilterChanges"++-- | Returns the number of most recent block.+blockNumber :: JsonRpc m => m Quantity+{-# INLINE blockNumber #-}+blockNumber = remote "eth_blockNumber"++-- | Returns the current price per gas in wei.+gasPrice :: JsonRpc m => m Quantity+{-# INLINE gasPrice #-}+gasPrice = remote "eth_gasPrice"++-- | Returns information about a uncle of a block by hash and uncle index+-- position.+getUncleByBlockHashAndIndex :: JsonRpc m => HexString -> Quantity -> m Block+{-# INLINE getUncleByBlockHashAndIndex #-}+getUncleByBlockHashAndIndex = remote "eth_getUncleByBlockHashAndIndex"++-- | Returns information about a uncle of a block by number and uncle index+-- position.+getUncleByBlockNumberAndIndex :: JsonRpc m => DefaultBlock -> Quantity -> m Block+{-# INLINE getUncleByBlockNumberAndIndex #-}+getUncleByBlockNumberAndIndex = remote "eth_getUncleByBlockNumberAndIndex"++-- | Creates a filter in the node, to notify when new pending transactions arrive. To check if the state has changed, call getFilterChanges. Returns a FilterId.+newPendingTransactionFilter :: JsonRpc m => m Quantity+{-# INLINE newPendingTransactionFilter #-}+newPendingTransactionFilter = remote "eth_newPendingTransactionFilter"++-- | Returns an array of all logs matching filter with given id.+getFilterLogs :: JsonRpc m => Quantity -> m [Change]+{-# INLINE getFilterLogs #-}+getFilterLogs = remote "eth_getFilterLogs"++-- | Returns the hash of the current block, the seedHash, and the boundary+-- condition to be met ("target").+getWork :: JsonRpc m => m [HexString]+{-# INLINE getWork #-}+getWork = remote "eth_getWork"++-- | Used for submitting a proof-of-work solution.+-- Parameters:+-- 1. DATA, 8 Bytes - The nonce found (64 bits)+-- 2. DATA, 32 Bytes - The header's pow-hash (256 bits)+-- 3. DATA, 32 Bytes - The mix digest (256 bits)+submitWork :: JsonRpc m => HexString -> HexString -> HexString -> m Bool+{-# INLINE submitWork #-}+submitWork = remote "eth_submitWork"++-- | Used for submitting mining hashrate.+-- Parameters:+-- 1. Hashrate, a hexadecimal string representation (32 bytes) of the hash rate+-- 2. ID, String - A random hexadecimal(32 bytes) ID identifying the client+submitHashrate :: JsonRpc m => HexString -> HexString -> m Bool+{-# INLINE submitHashrate #-}+submitHashrate = remote "eth_submitHashrate"
+ src/Network/Ethereum/Api/Net.hs view
@@ -0,0 +1,35 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}++-- |+-- Module : Network.Ethereum.Api.Net+-- Copyright : Alexander Krupenkin 2016-2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : unknown+--+-- Ethereum node JSON-RPC API methods with `net_` prefix.+--++module Network.Ethereum.Api.Net where++import Data.Text (Text)+import Network.Ethereum.Api.Types (Quantity)+import Network.JsonRpc.TinyClient (JsonRpc (..))++-- | Returns the current network id.+version :: JsonRpc m => m Text+{-# INLINE version #-}+version = remote "net_version"++-- | Returns true if client is actively listening for network connections.+listening :: JsonRpc m => m Bool+{-# INLINE listening #-}+listening = remote "net_listening"++-- | Returns number of peers currently connected to the client.+peerCount :: JsonRpc m => m Quantity+{-# INLINE peerCount #-}+peerCount = remote "net_peerCount"
+ src/Network/Ethereum/Api/Personal.hs view
@@ -0,0 +1,93 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}++-- |+-- Module : Network.Ethereum.Api.Personal+-- Copyright : Keagan McClelland 2018+-- License : BSD3+--+-- Maintainer : keagan.mcclelland@gmail.com+-- Stability : experimental+-- Portability : unknown+--+-- Ethereum node JSON-RPC API methods with `personal_` prefix.+--++module Network.Ethereum.Api.Personal where++import Data.ByteArray.HexString (HexString)+import Data.Solidity.Prim.Address (Address)+import Data.Text (Text)+import Network.Ethereum.Api.Types (Call)+import Network.JsonRpc.TinyClient (JsonRpc (..))++type Passphrase = Text++-- | Imports the given unencrypted private key (hex string) into the key store, encrypting it with the passphrase.+--+-- Parameters:+--+-- 1. unencrypted private key+--+-- 2. passphrase+--+-- Returns: address of new account+importRawKey :: JsonRpc m => HexString -> Passphrase -> m Address+{-# INLINE importRawKey #-}+importRawKey = remote "personal_importRawKey"++-- | Returns all the Ethereum account addresses of all keys in the key store.+listAccounts :: JsonRpc m => m [Address]+{-# INLINE listAccounts #-}+listAccounts = remote "personal_listAccounts"++-- | Removes the private key with given address from memory. The account can no longer be used to send transactions.+lockAccount :: JsonRpc m => Address -> m Bool+{-# INLINE lockAccount #-}+lockAccount = remote "personal_lockAccount"++-- | Generates a new private key and stores it in the key store directory. The key file is encrypted with the given+-- passphrase. Returns the address of the new account.+newAccount :: JsonRpc m => Passphrase -> m Address+{-# INLINE newAccount #-}+newAccount = remote "personal_newAccount"++-- | Decrypts the key with the given address from the key store.+--+-- The unencrypted key will be held in memory until it is locked again+--+-- The account can be used with eth_sign and eth_sendTransaction while it is unlocked.+unlockAccount :: JsonRpc m => Address -> Passphrase -> m Bool+{-# INLINE unlockAccount #-}+unlockAccount = remote "personal_unlockAccount"++-- | Validate the given passphrase and submit transaction.+--+-- The transaction is the same argument as for eth_sendTransaction and contains the from address. If the passphrase can+-- be used to decrypt the private key belonging to the transaction 'callFrom', the transaction is verified, signed and+-- send onto the network. The account is not unlocked globally in the node and cannot be used in other RPC calls.+sendTransaction :: JsonRpc m => Call -> Passphrase -> m HexString+{-# INLINE sendTransaction #-}+sendTransaction = remote "personal_sendTransaction"++-- | Returns an Ethereum specific signature with:+--+-- sign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))).+--+-- when given a passphrase to decrypt the account's private key+sign :: JsonRpc m => HexString -> Address -> Passphrase -> m HexString+{-# INLINE sign #-}+sign = remote "personal_sign"++-- | Recovers address given message and signature data+--+-- Parameters:+--+-- 1. message: DATA, n bytes+--+-- 2. signature: DATA, 65 bytes+--+-- Returns: Address+ecRecover :: JsonRpc m => HexString -> HexString -> m Address+{-# INLINE ecRecover #-}+ecRecover = remote "personal_ecRecover"
+ src/Network/Ethereum/Api/Provider.hs view
@@ -0,0 +1,87 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses #-}++-- |+-- Module : Network.Ethereum.Api.Provider+-- Copyright : Alexander Krupenkin 2016-2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : portable+--+-- Web3 service provider.+--++module Network.Ethereum.Api.Provider where++import Control.Concurrent.Async (Async, async)+import Control.Exception (Exception, try)+import Control.Monad.Catch (MonadThrow)+import Control.Monad.IO.Class (MonadIO (..))+import Control.Monad.State (MonadState (..))+import Control.Monad.Trans.State (StateT, evalStateT)+import Data.Default (Default (..))+import GHC.Generics (Generic)+import Lens.Micro.Mtl ((.=))+import Network.HTTP.Client (Manager)++import Network.JsonRpc.TinyClient (JsonRpc, JsonRpcClient,+ defaultSettings, jsonRpcManager)++-- | Any communication with Ethereum node wrapped with 'Web3' monad+newtype Web3 a = Web3 { unWeb3 :: StateT JsonRpcClient IO a }+ deriving (Functor, Applicative, Monad, MonadIO, MonadThrow, MonadState JsonRpcClient)++instance JsonRpc Web3++-- | Some peace of error response+data Web3Error+ = JsonRpcFail !String+ -- ^ JSON-RPC communication error+ | ParserFail !String+ -- ^ Error in parser state+ | UserFail !String+ -- ^ Common head for user errors+ deriving (Show, Eq, Generic)++instance Exception Web3Error++--TODO: Change to `HttpProvider ServerUri | IpcProvider FilePath` to support IPC+-- | Web3 Provider+data Provider = HttpProvider String+ deriving (Show, Eq, Generic)++instance Default Provider where+ def = HttpProvider "http://localhost:8545"++-- | 'Web3' monad runner, using the supplied Manager+runWeb3With :: MonadIO m+ => Manager+ -> Provider+ -> Web3 a+ -> m (Either Web3Error a)+runWeb3With manager provider f =+ runWeb3' provider $ jsonRpcManager .= manager >> f++-- | 'Web3' monad runner+runWeb3' :: MonadIO m+ => Provider+ -> Web3 a+ -> m (Either Web3Error a)+runWeb3' (HttpProvider uri) f = do+ cfg <- defaultSettings uri+ liftIO . try . flip evalStateT cfg . unWeb3 $ f++-- | 'Web3' runner for default provider+runWeb3 :: MonadIO m+ => Web3 a+ -> m (Either Web3Error a)+{-# INLINE runWeb3 #-}+runWeb3 = runWeb3' def++-- | Fork 'Web3' with the same 'Provider' and 'Manager'+forkWeb3 :: Web3 a -> Web3 (Async a)+forkWeb3 f = liftIO . async . evalStateT (unWeb3 f) =<< get
+ src/Network/Ethereum/Api/Types.hs view
@@ -0,0 +1,298 @@+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++-- |+-- Module : Network.Ethereum.Api.Types+-- Copyright : Alexander Krupenkin 2016-2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : portable+--+-- Ethereum generic JSON-RPC types.+--++module Network.Ethereum.Api.Types where++import Data.Aeson (FromJSON (..), Options (fieldLabelModifier, omitNothingFields),+ ToJSON (..), Value (Bool, String),+ defaultOptions, object, (.=))+import Data.Aeson.TH (deriveJSON)+import Data.Default (Default (..))+import Data.Monoid ((<>))+import Data.Solidity.Prim.Address (Address)+import Data.String (IsString (..))+import qualified Data.Text as T (pack)+import qualified Data.Text.Lazy.Builder as B (toLazyText)+import qualified Data.Text.Lazy.Builder.Int as B (hexadecimal)+import qualified Data.Text.Read as R (decimal, hexadecimal)+import GHC.Generics (Generic)++import Data.ByteArray.HexString (HexString)+import Data.String.Extra (toLowerFirst)++-- | Should be viewed as type to representing QUANTITY in Web3 JSON RPC docs+--+-- When encoding QUANTITIES (integers, numbers): encode as hex, prefix with "0x",+-- the most compact representation (slight exception: zero should be represented as "0x0").+-- Examples:+--+-- 0x41 (65 in decimal)+-- 0x400 (1024 in decimal)+-- WRONG: 0x (should always have at least one digit - zero is "0x0")+-- WRONG: 0x0400 (no leading zeroes allowed)+-- WRONG: ff (must be prefixed 0x)+newtype Quantity = Quantity { unQuantity :: Integer }+ deriving (Num, Real, Integral, Enum, Eq, Ord, Generic)++instance Show Quantity where+ show = show . unQuantity++instance IsString Quantity where+ fromString ('0' : 'x' : hex) =+ case R.hexadecimal (T.pack hex) of+ Right (x, "") -> Quantity x+ _ -> error ("Quantity " ++ show hex ++ " is not valid hex")+ fromString num =+ case R.decimal (T.pack num) of+ Right (x, "") -> Quantity x+ _ -> error ("Quantity " ++ show num ++ " is not valid decimal")++instance ToJSON Quantity where+ toJSON (Quantity x) =+ let hexValue = B.toLazyText (B.hexadecimal x)+ in toJSON ("0x" <> hexValue)++instance FromJSON Quantity where+ parseJSON (String v) =+ case R.hexadecimal v of+ Right (x, "") -> return (Quantity x)+ _ -> fail $ "Quantity " ++ show v <> " is not valid hex"+ parseJSON _ = fail "Quantity should be a JSON String"++-- | An object with sync status data.+data SyncActive = SyncActive+ { syncStartingBlock :: !Quantity+ -- ^ QUANTITY - The block at which the import started (will only be reset, after the sync reached his head).+ , syncCurrentBlock :: !Quantity+ -- ^ QUANTITY - The current block, same as eth_blockNumber.+ , syncHighestBlock :: !Quantity+ -- ^ QUANTITY - The estimated highest block.+ } deriving (Eq, Generic, Show)++$(deriveJSON (defaultOptions+ { fieldLabelModifier = toLowerFirst . drop 4 }) ''SyncActive)++-- | Sync state pulled by low-level call 'eth_syncing'.+data SyncingState = Syncing SyncActive | NotSyncing+ deriving (Eq, Generic, Show)++instance FromJSON SyncingState where+ parseJSON (Bool _) = pure NotSyncing+ parseJSON v = Syncing <$> parseJSON v++-- | Changes pulled by low-level call 'eth_getFilterChanges', 'eth_getLogs',+-- and 'eth_getFilterLogs'+data Change = Change+ { changeLogIndex :: !(Maybe Quantity)+ -- ^ QUANTITY - integer of the log index position in the block. null when its pending log.+ , changeTransactionIndex :: !(Maybe Quantity)+ -- ^ QUANTITY - integer of the transactions index position log was created from. null when its pending log.+ , changeTransactionHash :: !(Maybe HexString)+ -- ^ DATA, 32 Bytes - hash of the transactions this log was created from. null when its pending log.+ , changeBlockHash :: !(Maybe HexString)+ -- ^ DATA, 32 Bytes - hash of the block where this log was in. null when its pending. null when its pending log.+ , changeBlockNumber :: !(Maybe Quantity)+ -- ^ QUANTITY - the block number where this log was in. null when its pending. null when its pending log.+ , changeAddress :: !Address+ -- ^ DATA, 20 Bytes - address from which this log originated.+ , changeData :: !HexString+ -- ^ DATA - contains one or more 32 Bytes non-indexed arguments of the log.+ , changeTopics :: ![HexString]+ -- ^ Array of DATA - Array of 0 to 4 32 Bytes DATA of indexed log arguments.+ -- (In solidity: The first topic is the hash of the signature of the event+ -- (e.g. Deposit(address, bytes32, uint256)), except you declared the event with+ -- the anonymous specifier.)+ } deriving (Eq, Show, Generic)++$(deriveJSON (defaultOptions+ { fieldLabelModifier = toLowerFirst . drop 6 }) ''Change)++-- | The contract call params.+data Call = Call+ { callFrom :: !(Maybe Address)+ -- ^ DATA, 20 Bytes - The address the transaction is send from.+ , callTo :: !(Maybe Address)+ -- ^ DATA, 20 Bytes - (optional when creating new contract) The address the transaction is directed to.+ , callGas :: !(Maybe Quantity)+ -- ^ QUANTITY - (optional, default: 3000000) Integer of the gas provided for the transaction execution. It will return unused gas.+ , callGasPrice :: !(Maybe Quantity)+ -- ^ QUANTITY - (optional, default: To-Be-Determined) Integer of the gasPrice used for each paid gas.+ , callValue :: !(Maybe Quantity)+ -- ^ QUANTITY - (optional) Integer of the value sent with this transaction.+ , callData :: !(Maybe HexString)+ -- ^ DATA - The compiled code of a contract OR the hash of the invoked method signature and encoded parameters.+ , callNonce :: !(Maybe Quantity)+ -- ^ QUANTITY - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce.+ } deriving (Eq, Show, Generic)++$(deriveJSON (defaultOptions+ { fieldLabelModifier = toLowerFirst . drop 4+ , omitNothingFields = True }) ''Call)++instance Default Call where+ def = Call Nothing Nothing (Just 3000000) Nothing (Just 0) Nothing Nothing++-- | The state of blockchain for contract call.+data DefaultBlock = BlockWithNumber Quantity+ | Earliest+ | Latest+ | Pending+ deriving (Eq, Show, Generic)++instance ToJSON DefaultBlock where+ toJSON (BlockWithNumber bn) = toJSON bn+ toJSON parameter = toJSON . toLowerFirst . show $ parameter++-- | Low-level event filter data structure.+data Filter e = Filter+ { filterAddress :: !(Maybe [Address])+ -- ^ DATA|Array, 20 Bytes - (optional) Contract address or a list of addresses from which logs should originate.+ , filterFromBlock :: !DefaultBlock+ -- ^ QUANTITY|TAG - (optional, default: "latest") Integer block number, or "latest" for the last mined block or "pending", "earliest" for not yet mined transactions.+ , filterToBlock :: !DefaultBlock+ -- ^ QUANTITY|TAG - (optional, default: "latest") Integer block number, or "latest" for the last mined block or "pending", "earliest" for not yet mined transactions.+ , filterTopics :: !(Maybe [Maybe HexString])+ -- ^ Array of DATA, - (optional) Array of 32 Bytes DATA topics. Topics are order-dependent. Each topic can also be an array of DATA with "or" options.+ -- Topics are order-dependent. A transaction with a log with topics [A, B] will be matched by the following topic filters:+ -- * [] "anything"+ -- * [A] "A in first position (and anything after)"+ -- * [null, B] "anything in first position AND B in second position (and anything after)"+ -- * [A, B] "A in first position AND B in second position (and anything after)"+ -- * [[A, B], [A, B]] "(A OR B) in first position AND (A OR B) in second position (and anything after)"+ } deriving (Eq, Show, Generic)++instance ToJSON (Filter e) where+ toJSON f = object [ "address" .= filterAddress f+ , "fromBlock" .= filterFromBlock f+ , "toBlock" .= filterToBlock f+ , "topics" .= filterTopics f ]++instance Ord DefaultBlock where+ compare Pending Pending = EQ+ compare Latest Latest = EQ+ compare Earliest Earliest = EQ+ compare (BlockWithNumber a) (BlockWithNumber b) = compare a b+ compare _ Pending = LT+ compare Pending Latest = GT+ compare _ Latest = LT+ compare Earliest _ = LT+ compare a b = case compare b a of+ LT -> GT+ GT -> LT+ EQ -> EQ++-- | The Receipt of a Transaction+data TxReceipt = TxReceipt+ { receiptTransactionHash :: !HexString+ -- ^ DATA, 32 Bytes - hash of the transaction.+ , receiptTransactionIndex :: !Quantity+ -- ^ QUANTITY - index of the transaction.+ , receiptBlockHash :: !(Maybe HexString)+ -- ^ DATA, 32 Bytes - hash of the block where this transaction was in. null when its pending.+ , receiptBlockNumber :: !(Maybe Quantity)+ -- ^ QUANTITY - block number where this transaction was in. null when its pending.+ , receiptCumulativeGasUsed :: !Quantity+ -- ^ QUANTITY - The total amount of gas used when this transaction was executed in the block.+ , receiptGasUsed :: !Quantity+ -- ^ QUANTITY - The amount of gas used by this specific transaction alone.+ , receiptContractAddress :: !(Maybe Address)+ -- ^ DATA, 20 Bytes - The contract address created, if the transaction was a contract creation, otherwise null.+ , receiptLogs :: ![Change]+ -- ^ Array - Array of log objects, which this transaction generated.+ , receiptLogsBloom :: !HexString+ -- ^ DATA, 256 Bytes - Bloom filter for light clients to quickly retrieve related logs.+ , receiptStatus :: !(Maybe Quantity)+ -- ^ QUANTITY either 1 (success) or 0 (failure)+ } deriving (Show, Generic)++$(deriveJSON (defaultOptions+ { fieldLabelModifier = toLowerFirst . drop 7 }) ''TxReceipt)++-- | Transaction information.+data Transaction = Transaction+ { txHash :: !HexString+ -- ^ DATA, 32 Bytes - hash of the transaction.+ , txNonce :: !Quantity+ -- ^ QUANTITY - the number of transactions made by the sender prior to this one.+ , txBlockHash :: !(Maybe HexString)+ -- ^ DATA, 32 Bytes - hash of the block where this transaction was in. null when its pending.+ , txBlockNumber :: !(Maybe Quantity)+ -- ^ QUANTITY - block number where this transaction was in. null when its pending.+ , txTransactionIndex :: !(Maybe Quantity)+ -- ^ QUANTITY - integer of the transactions index position in the block. null when its pending.+ , txFrom :: !Address+ -- ^ DATA, 20 Bytes - address of the sender.+ , txTo :: !(Maybe Address)+ -- ^ DATA, 20 Bytes - address of the receiver. null when its a contract creation transaction.+ , txValue :: !Quantity+ -- ^ QUANTITY - value transferred in Wei.+ , txGasPrice :: !Quantity+ -- ^ QUANTITY - gas price provided by the sender in Wei.+ , txGas :: !Quantity+ -- ^ QUANTITY - gas provided by the sender.+ , txInput :: !HexString+ -- ^ DATA - the data send along with the transaction.+ } deriving (Eq, Show, Generic)++$(deriveJSON (defaultOptions+ { fieldLabelModifier = toLowerFirst . drop 2 }) ''Transaction)++-- | Block information.+data Block = Block+ { blockNumber :: !(Maybe Quantity)+ -- ^ QUANTITY - the block number. null when its pending block.+ , blockHash :: !(Maybe HexString)+ -- ^ DATA, 32 Bytes - hash of the block. null when its pending block.+ , blockParentHash :: !HexString+ -- ^ DATA, 32 Bytes - hash of the parent block.+ , blockNonce :: !(Maybe HexString)+ -- ^ DATA, 8 Bytes - hash of the generated proof-of-work. null when its pending block.+ , blockSha3Uncles :: !HexString+ -- ^ DATA, 32 Bytes - SHA3 of the uncles data in the block.+ , blockLogsBloom :: !(Maybe HexString)+ -- ^ DATA, 256 Bytes - the bloom filter for the logs of the block. null when its pending block.+ , blockTransactionsRoot :: !HexString+ -- ^ DATA, 32 Bytes - the root of the transaction trie of the block.+ , blockStateRoot :: !HexString+ -- ^ DATA, 32 Bytes - the root of the final state trie of the block.+ , blockReceiptRoot :: !(Maybe HexString)+ -- ^ DATA, 32 Bytes - the root of the receipts trie of the block.+ , blockMiner :: !Address+ -- ^ DATA, 20 Bytes - the address of the beneficiary to whom the mining rewards were given.+ , blockDifficulty :: !Quantity+ -- ^ QUANTITY - integer of the difficulty for this block.+ , blockTotalDifficulty :: !Quantity+ -- ^ QUANTITY - integer of the total difficulty of the chain until this block.+ , blockExtraData :: !HexString+ -- ^ DATA - the "extra data" field of this block.+ , blockSize :: !Quantity+ -- ^ QUANTITY - integer the size of this block in bytes.+ , blockGasLimit :: !Quantity+ -- ^ QUANTITY - the maximum gas allowed in this block.+ , blockGasUsed :: !Quantity+ -- ^ QUANTITY - the total used gas by all transactions in this block.+ , blockTimestamp :: !Quantity+ -- ^ QUANTITY - the unix timestamp for when the block was collated.+ , blockTransactions :: ![Transaction]+ -- ^ Array of transaction objects.+ , blockUncles :: ![HexString]+ -- ^ Array - Array of uncle hashes.+ } deriving (Show, Generic)++$(deriveJSON (defaultOptions+ { fieldLabelModifier = toLowerFirst . drop 5 }) ''Block)
+ src/Network/Ethereum/Api/Web3.hs view
@@ -0,0 +1,30 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}++-- |+-- Module : Network.Ethereum.Api.Web3+-- Copyright : Alexander Krupenkin 2016-2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : unknown+--+-- Ethereum node JSON-RPC API methods with `web3_` prefix.+--++module Network.Ethereum.Api.Web3 where++import Data.ByteArray.HexString (HexString)+import Data.Text (Text)+import Network.JsonRpc.TinyClient (JsonRpc (..))++-- | Returns current node version string.+clientVersion :: JsonRpc m => m Text+{-# INLINE clientVersion #-}+clientVersion = remote "web3_clientVersion"++-- | Returns Keccak-256 (not the standardized SHA3-256) of the given data.+sha3 :: JsonRpc m => HexString -> m HexString+{-# INLINE sha3 #-}+sha3 = remote "web3_sha3"
+ src/Network/Ethereum/Chain.hs view
@@ -0,0 +1,36 @@+-- |+-- Module : Network.Ethereum.Chain+-- Copyright : Alexander Krupenkin 2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : unportable+--+--++module Network.Ethereum.Chain where++-- | Ethereum mainnet CHAIN_ID from EIP155+foundation :: Integer+foundation = 1++-- | Ethereum testnet CHAIN_ID from EIP155+ropsten :: Integer+ropsten = 3++-- | Rokenby CHAIN_ID from EIP155+rikenby :: Integer+rikenby = 4++-- | Kovan CHAIN_ID from EIP155+kovan :: Integer+kovan = 42++-- | Ethereum Classic mainnet CHAIN_ID from EIP155+classic :: Integer+classic = 61++-- | Ethereum Classic testnet CHAIN_ID from EIP155+classicTestnet :: Integer+classicTestnet = 62
+ src/Network/Ethereum/Contract.hs view
@@ -0,0 +1,49 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeSynonymInstances #-}++-- |+-- Module : Network.Ethereum.Contract+-- Copyright : Alexander Krupenkin 2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : unportable+--+-- Smart contract type class and utils. A contract in the sense of Solidity+-- is a collection of code (its functions) and data (its state) that resides+-- at a specific address on the Ethereum blockchain.+--++module Network.Ethereum.Contract where++import Data.Proxy (Proxy)+import Data.Text (Text)++import Data.ByteArray.HexString (HexString)+import Data.Solidity.Prim.Address (Address)+import Network.Ethereum.Account.Class (Account)+import Network.Ethereum.Account.Safe (safeConfirmations, safeSend)+import Network.Ethereum.Api.Types (receiptContractAddress)+import Network.Ethereum.Contract.Method (Method)+import Network.JsonRpc.TinyClient (JsonRpc)++-- | Contract description type clase+class Contract a where+ -- | Contract Solidity ABI+ -- https://solidity.readthedocs.io/en/latest/abi-spec.html+ abi :: Proxy a -> Text++ -- | Contract bytecode as hex string+ bytecode :: Proxy a -> HexString++-- | 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+new = fmap receiptContractAddress . safeSend safeConfirmations
src/Network/Ethereum/Contract/Event.hs view
@@ -1,11 +1,6 @@-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeFamilies #-}- -- | -- Module : Network.Ethereum.Contract.Event--- Copyright : Alexander Krupenkin 2016-2018+-- Copyright : Alexander Krupenkin 2016 -- License : BSD3 -- -- Maintainer : mail@akru.me@@ -15,183 +10,13 @@ -- Ethereum contract event support. -- -module Network.Ethereum.Contract.Event (- EventAction(..)- , event- , event'- , eventMany'- ) where--import Control.Concurrent (threadDelay)-import Control.Monad (forM, void, when)-import Control.Monad.IO.Class (liftIO)-import Control.Monad.Trans.Class (lift)-import Control.Monad.Trans.Reader (ReaderT (..))-import Data.Either (rights)-import Data.Machine (MachineT, asParts, autoM,- await, construct, final,- mapping, repeatedly, runT,- unfoldPlan, (~>))-import Data.Machine.Plan (PlanT, stop, yield)-import Data.Maybe (catMaybes, listToMaybe)--import Control.Concurrent.Async (Async)-import Network.Ethereum.ABI.Event (DecodeEvent (..))-import qualified Network.Ethereum.Web3.Eth as Eth-import Network.Ethereum.Web3.Provider (Web3, forkWeb3)-import Network.Ethereum.Web3.Types (Change (..), DefaultBlock (..),- Filter (..), Quantity)---- | Event callback control response-data EventAction = ContinueEvent- -- ^ Continue to listen events- | TerminateEvent- -- ^ Terminate event listener- deriving (Show, Eq)---- | Run 'event\'' one block at a time.-event :: DecodeEvent i ni e- => Filter e- -> (e -> ReaderT Change Web3 EventAction)- -> Web3 (Async ())-event fltr = forkWeb3 . event' fltr---- | Same as 'event', but does not immediately spawn a new thread.-event' :: DecodeEvent i ni e- => Filter e- -> (e -> ReaderT Change Web3 EventAction)- -> Web3 ()-event' fltr = eventMany' fltr 0---- | 'eventMany\'' take s a filter, a window size, and a handler.------ It runs the handler over the results of 'eventLogs' results using--- 'reduceEventStream'. If no 'TerminateEvent' action is thrown and--- the toBlock is not yet reached, it then transitions to polling.----eventMany' :: DecodeEvent i ni e- => Filter e- -> Integer- -> (e -> ReaderT Change Web3 EventAction)- -> Web3 ()-eventMany' fltr window handler = do- start <- mkBlockNumber $ filterFromBlock fltr- let initState = FilterStreamState { fssCurrentBlock = start- , fssInitialFilter = fltr- , fssWindowSize = window- }- mLastProcessedFilterState <- reduceEventStream (playLogs initState) handler- case mLastProcessedFilterState of- Nothing -> startPolling fltr {filterFromBlock = BlockWithNumber start}- Just (act, lastBlock) -> do- end <- mkBlockNumber . filterToBlock $ fltr- when (act /= TerminateEvent && lastBlock < end) $- let pollingFromBlock = lastBlock + 1- in startPolling fltr {filterFromBlock = BlockWithNumber pollingFromBlock}- where- startPolling fltr' = do- filterId <- Eth.newFilter fltr'- let pollTo = filterToBlock fltr'- void $ reduceEventStream (pollFilter filterId pollTo) handler---- | Effectively a mapM_ over the machine using the given handler.-reduceEventStream :: Monad m- => MachineT m k [FilterChange a]- -> (a -> ReaderT Change m EventAction)- -> m (Maybe (EventAction, Quantity))-reduceEventStream filterChanges handler = fmap listToMaybe . runT $- filterChanges- ~> autoM (processChanges handler)- ~> asParts- ~> runWhile (\(act, _) -> act /= TerminateEvent)- ~> final- where- runWhile p = repeatedly $ do- v <- await- if p v- then yield v- else yield v >> stop- processChanges :: Monad m- => (a -> ReaderT Change m EventAction)- -> [FilterChange a]- -> m [(EventAction, Quantity)]- processChanges handler' changes = fmap catMaybes $- forM changes $ \FilterChange{..} -> do- act <- flip runReaderT filterChangeRawChange $- handler' filterChangeEvent- return ((,) act <$> changeBlockNumber filterChangeRawChange)--data FilterChange a = FilterChange { filterChangeRawChange :: Change- , filterChangeEvent :: a- }---- | 'playLogs' streams the 'filterStream' and calls eth_getLogs on these 'Filter' objects.-playLogs :: DecodeEvent i ni e- => FilterStreamState e- -> MachineT Web3 k [FilterChange e]-playLogs s = filterStream s- ~> autoM Eth.getLogs- ~> mapping mkFilterChanges---- | Polls a filter from the given filterId until the target toBlock is reached.-pollFilter :: forall i ni e k . DecodeEvent i ni e- => Quantity- -> DefaultBlock- -> MachineT Web3 k [FilterChange e]-pollFilter i = construct . pollPlan i- where- pollPlan :: Quantity -> DefaultBlock -> PlanT k [FilterChange e] Web3 ()- pollPlan fid end = do- bn <- lift $ Eth.blockNumber- if BlockWithNumber bn > end- then do- _ <- lift $ Eth.uninstallFilter fid- stop- else do- liftIO $ threadDelay 1000000- changes <- lift $ Eth.getFilterChanges fid- yield $ mkFilterChanges changes- pollPlan fid end--mkFilterChanges :: DecodeEvent i ni e- => [Change]- -> [FilterChange e]-mkFilterChanges = rights- . fmap (\c@Change{..} -> FilterChange c <$> decodeEvent c)--data FilterStreamState e =- FilterStreamState { fssCurrentBlock :: Quantity- , fssInitialFilter :: Filter e- , fssWindowSize :: Integer- }----- | 'filterStream' is a machine which represents taking an initial filter--- over a range of blocks b1, ... bn (where bn is possibly `Latest` or `Pending`,--- but b1 is an actual block number), and making a stream of filter objects--- which cover this filter in intervals of size `windowSize`. The machine--- halts whenever the `fromBlock` of a spanning filter either (1) excedes then--- initial filter's `toBlock` or (2) is greater than the chain head's block number.-filterStream :: FilterStreamState e- -> MachineT Web3 k (Filter e)-filterStream initialPlan = unfoldPlan initialPlan filterPlan- where- filterPlan :: FilterStreamState e -> PlanT k (Filter e) Web3 (FilterStreamState e)- filterPlan initialState@FilterStreamState{..} = do- end <- lift . mkBlockNumber $ filterToBlock fssInitialFilter- if fssCurrentBlock > end- then stop- else do- let to' = min end $ fssCurrentBlock + fromInteger fssWindowSize- filter' = fssInitialFilter { filterFromBlock = BlockWithNumber fssCurrentBlock- , filterToBlock = BlockWithNumber to'- }- yield filter'- filterPlan $ initialState { fssCurrentBlock = to' + 1 }+module Network.Ethereum.Contract.Event+ (+ module Network.Ethereum.Contract.Event.Common+ , module Network.Ethereum.Contract.Event.SingleFilter+ , module Network.Ethereum.Contract.Event.MultiFilter+ ) where --- | Coerce a 'DefaultBlock' into a numerical block number.-mkBlockNumber :: DefaultBlock -> Web3 Quantity-mkBlockNumber bm = case bm of- BlockWithNumber bn -> return bn- Earliest -> return 0- _ -> Eth.blockNumber+import Network.Ethereum.Contract.Event.Common+import Network.Ethereum.Contract.Event.MultiFilter+import Network.Ethereum.Contract.Event.SingleFilter
+ src/Network/Ethereum/Contract/Event/Common.hs view
@@ -0,0 +1,86 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE UndecidableInstances #-}++-- |+-- Module : Network.Ethereum.Contract.Event.Common+-- Copyright : FOAM team <http://foam.space> 2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : unportable+--+-- Common event manipulation functions.+--++module Network.Ethereum.Contract.Event.Common where++import Control.Concurrent (threadDelay)+import Control.Exception (Exception, throwIO)+import Control.Monad.IO.Class (liftIO)+import Data.Either (lefts, rights)++import Data.Solidity.Event (DecodeEvent (..))+import qualified Network.Ethereum.Api.Eth as Eth+import Network.Ethereum.Api.Provider (Web3)+import Network.Ethereum.Api.Types (Change (..), DefaultBlock (..),+ Filter (..), Quantity)++-- | Event callback control response+data EventAction = ContinueEvent+ -- ^ Continue to listen events+ | TerminateEvent+ -- ^ Terminate event listener+ deriving (Show, Eq)+++data FilterChange a =+ FilterChange { filterChangeRawChange :: Change+ , filterChangeEvent :: a+ }++data EventParseFailure = EventParseFailure String deriving (Show)++instance Exception EventParseFailure++mkFilterChanges :: DecodeEvent i ni e+ => [Change]+ -> IO [FilterChange e]+mkFilterChanges changes =+ let eChanges = map (\c@Change{..} -> FilterChange c <$> decodeEvent c) changes+ ls = lefts eChanges+ rs = rights eChanges+ in if ls /= [] then throwIO (EventParseFailure $ show ls) else pure rs+++data FilterStreamState e =+ FilterStreamState { fssCurrentBlock :: Quantity+ , fssInitialFilter :: Filter e+ , fssWindowSize :: Integer+ }+++-- | Coerce a 'DefaultBlock' into a numerical block number.+mkBlockNumber :: DefaultBlock -> Web3 Quantity+mkBlockNumber bm = case bm of+ BlockWithNumber bn -> return bn+ Earliest -> return 0+ _ -> Eth.blockNumber+++pollTillBlockProgress+ :: Quantity+ -> Web3 Quantity+pollTillBlockProgress currentBlock = do+ bn <- Eth.blockNumber+ if currentBlock >= bn+ then do+ liftIO $ threadDelay 3000000+ pollTillBlockProgress currentBlock+ else pure bn
+ src/Network/Ethereum/Contract/Event/MultiFilter.hs view
@@ -0,0 +1,457 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeFamilyDependencies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}++-- |+-- Module : Network.Ethereum.Contract.Event.MultiFilter+-- Copyright : FOAM team <http://foam.space> 2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : unportable+--+-- Support for parallel multiple event filters.+--++module Network.Ethereum.Contract.Event.MultiFilter+ (+ -- * The @MultiFilter@ type+ MultiFilter(..)+ , minStartBlock+ , minEndBlock+ , modifyMultiFilter++ -- * With geth filters+ , multiEvent+ , multiEvent'+ , multiEventMany'++ -- * Without geth filters+ , multiEventNoFilter+ , multiEventNoFilter'+ , multiEventManyNoFilter'++ -- * Re-exports+ , Handlers+ , Handler(..)+ , Rec(..)+ ) where++import Control.Concurrent (threadDelay)+import Control.Concurrent.Async (Async)+import Control.Monad (forM, void, when)+import Control.Monad.IO.Class (MonadIO (..))+import Control.Monad.Trans.Class (lift)+import Control.Monad.Trans.Reader (ReaderT (..))+import Data.List (sortOn)+import Data.Machine (MachineT, asParts,+ autoM, await,+ construct, final,+ repeatedly, runT,+ unfoldPlan, (~>))+import Data.Machine.Plan (PlanT, stop, yield)+import Data.Maybe (catMaybes, fromJust,+ listToMaybe)+import Data.Monoid ((<>))+import Data.Proxy (Proxy (..))+import Data.Tagged (Tagged (..))+import Data.Vinyl (Rec ((:&), RNil),+ RecApplicative)+import Data.Vinyl.CoRec (CoRec (..), Field,+ FoldRec, Handler (H),+ Handlers, coRecToRec,+ firstField, match,+ onField)+import Data.Vinyl.Functor (Compose (..),+ Identity (..))+import Data.Vinyl.TypeLevel (AllAllSat)++import Data.Solidity.Event (DecodeEvent (..))+import qualified Network.Ethereum.Api.Eth as Eth+import Network.Ethereum.Api.Provider (Web3, forkWeb3)+import Network.Ethereum.Api.Types (Change (..),+ DefaultBlock (..),+ Filter (..), Quantity)+import Network.Ethereum.Contract.Event.Common++--------------------------------------------------------------------------------+-- | MultiFilters+--------------------------------------------------------------------------------++data MultiFilter (es :: [*]) where+ NilFilters :: MultiFilter '[]+ (:?) :: Filter e -> MultiFilter es -> MultiFilter (e ': es)++infixr 5 :?++minEndBlock+ :: MultiFilter es+ -> DefaultBlock+minEndBlock NilFilters = Pending+minEndBlock (Filter _ _ e _ :? fs) = e `min` minEndBlock fs++minStartBlock+ :: MultiFilter es+ -> DefaultBlock+minStartBlock NilFilters = Pending+minStartBlock (Filter _ s _ _ :? fs) = s `min` minStartBlock fs++modifyMultiFilter+ :: (forall e. Filter e -> Filter e)+ -> MultiFilter es+ -> MultiFilter es+modifyMultiFilter _ NilFilters = NilFilters+modifyMultiFilter h (f :? fs) = h f :? modifyMultiFilter h fs+++multiEvent+ :: ( PollFilters es+ , QueryAllLogs es+ , MapHandlers Web3 es (WithChange es)+ , AllAllSat '[HasLogIndex] (WithChange es)+ , RecApplicative (WithChange es)+ )+ => MultiFilter es+ -> Handlers es (ReaderT Change Web3 EventAction)+ -> Web3 (Async ())+multiEvent fltrs = forkWeb3 . multiEvent' fltrs++multiEvent'+ :: ( PollFilters es+ , QueryAllLogs es+ , MapHandlers Web3 es (WithChange es)+ , AllAllSat '[HasLogIndex] (WithChange es)+ , RecApplicative (WithChange es)+ )+ => MultiFilter es+ -> Handlers es (ReaderT Change Web3 EventAction)+ -> Web3 ()+multiEvent' fltrs = multiEventMany' fltrs 0++data MultiFilterStreamState es =+ MultiFilterStreamState { mfssCurrentBlock :: Quantity+ , mfssInitialMultiFilter :: MultiFilter es+ , mfssWindowSize :: Integer+ }+++multiEventMany'+ :: ( PollFilters es+ , QueryAllLogs es+ , MapHandlers Web3 es (WithChange es)+ , AllAllSat '[HasLogIndex] (WithChange es)+ , RecApplicative (WithChange es)+ )+ => MultiFilter es+ -> Integer+ -> Handlers es (ReaderT Change Web3 EventAction)+ -> Web3 ()+multiEventMany' fltrs window handlers = do+ start <- mkBlockNumber $ minStartBlock fltrs+ let initState =+ MultiFilterStreamState { mfssCurrentBlock = start+ , mfssInitialMultiFilter = fltrs+ , mfssWindowSize = window+ }+ mLastProcessedFilterState <- reduceMultiEventStream (playMultiLogs initState) handlers+ case mLastProcessedFilterState of+ Nothing -> startPolling (modifyMultiFilter (\f -> f {filterFromBlock = BlockWithNumber start}) fltrs)+ Just (act, lastBlock) -> do+ end <- mkBlockNumber . minEndBlock $ fltrs+ when (act /= TerminateEvent && lastBlock < end) $+ let pollingFromBlock = lastBlock + 1+ in startPolling (modifyMultiFilter (\f -> f {filterFromBlock = BlockWithNumber pollingFromBlock}) fltrs)+ where+ startPolling fltrs' = do+ fIds <- openMultiFilter fltrs'+ let pollTo = minEndBlock fltrs'+ void $ reduceMultiEventStream (pollMultiFilter fIds pollTo) handlers++multiFilterStream+ :: MultiFilterStreamState es+ -> MachineT Web3 k (MultiFilter es)+multiFilterStream initialPlan = do+ unfoldPlan initialPlan $ \s -> do+ end <- lift . mkBlockNumber . minEndBlock . mfssInitialMultiFilter $ initialPlan+ filterPlan end s+ where+ filterPlan :: Quantity -> MultiFilterStreamState es -> PlanT k (MultiFilter es) Web3 (MultiFilterStreamState es)+ filterPlan end initialState@MultiFilterStreamState{..} = do+ if mfssCurrentBlock > end+ then stop+ else do+ let to' = min end $ mfssCurrentBlock + fromInteger mfssWindowSize+ h :: forall e. Filter e -> Filter e+ h f = f { filterFromBlock = BlockWithNumber mfssCurrentBlock+ , filterToBlock = BlockWithNumber to'+ }+ yield (modifyMultiFilter h mfssInitialMultiFilter)+ filterPlan end initialState { mfssCurrentBlock = to' + 1 }++weakenCoRec+ :: ( RecApplicative ts+ , FoldRec (t ': ts) (t ': ts)+ )+ => Field ts+ -> Field (t ': ts)+weakenCoRec = fromJust . firstField . (Compose Nothing :&) . coRecToRec++type family WithChange (es :: [*]) = (es' :: [*]) | es' -> es where+ WithChange '[] = '[]+ WithChange (e : es) = FilterChange e : WithChange es++class QueryAllLogs (es :: [*]) where+ queryAllLogs :: MultiFilter es -> Web3 [Field (WithChange es)]++instance QueryAllLogs '[] where+ queryAllLogs NilFilters = pure []++instance forall e i ni es.+ ( DecodeEvent i ni e+ , QueryAllLogs es+ , RecApplicative (WithChange es)+ , FoldRec (FilterChange e : WithChange es) (WithChange es)+ ) => QueryAllLogs (e:es) where++ queryAllLogs (f :? fs) = do+ changes <- Eth.getLogs f+ filterChanges <- liftIO . mkFilterChanges @_ @_ @e $ changes+ filterChanges' <- queryAllLogs fs+ pure $ map (CoRec . Identity) filterChanges <> map weakenCoRec filterChanges'++class HasLogIndex a where+ getLogIndex :: a -> Maybe (Quantity, Quantity)++instance HasLogIndex (FilterChange e) where+ getLogIndex FilterChange{..} =+ (,) <$> changeBlockNumber filterChangeRawChange <*> changeLogIndex filterChangeRawChange++sortChanges+ :: ( AllAllSat '[HasLogIndex] es+ , RecApplicative es+ )+ => [Field es]+ -> [Field es]+sortChanges changes =+ let sorterProj change = onField (Proxy @'[HasLogIndex]) getLogIndex change+ in sortOn sorterProj changes++class MapHandlers m es es' where+ mapHandlers+ :: Handlers es (ReaderT Change m EventAction)+ -> Handlers es' (m (Maybe (EventAction, Quantity)))++instance Monad m => MapHandlers m '[] '[] where+ mapHandlers RNil = RNil++instance+ ( Monad m+ , MapHandlers m es es'+ ) => MapHandlers m (e : es) (FilterChange e : es') where++ mapHandlers (H f :& fs) =+ let f' FilterChange{..} = do+ act <- runReaderT (f filterChangeEvent) filterChangeRawChange+ return ((,) act <$> changeBlockNumber filterChangeRawChange)+ in H f' :& mapHandlers fs+++reduceMultiEventStream+ :: ( Monad m+ , MapHandlers m es (WithChange es)+ )+ => MachineT m k [Field (WithChange es)]+ -> Handlers es (ReaderT Change m EventAction)+ -> m (Maybe (EventAction, Quantity))+reduceMultiEventStream filterChanges handlers = fmap listToMaybe . runT $+ filterChanges+ ~> autoM (processChanges handlers)+ ~> asParts+ ~> runWhile (\(act, _) -> act /= TerminateEvent)+ ~> final+ where+ runWhile p = repeatedly $ do+ v <- await+ if p v+ then yield v+ else yield v >> stop+ processChanges handlers' changes = fmap catMaybes $+ forM changes $ \fc -> match fc (mapHandlers handlers')++-- | 'playLogs' streams the 'filterStream' and calls eth_getLogs on these 'Filter' objects.+playMultiLogs+ :: forall es k.+ ( QueryAllLogs es+ , AllAllSat '[HasLogIndex] (WithChange es)+ , RecApplicative (WithChange es)+ )+ => MultiFilterStreamState es+ -> MachineT Web3 k [Field (WithChange es)]+playMultiLogs s = fmap sortChanges $+ multiFilterStream s+ ~> autoM queryAllLogs++data TaggedFilterIds (es :: [*]) where+ TaggedFilterNil :: TaggedFilterIds '[]+ TaggedFilterCons :: Tagged e Quantity -> TaggedFilterIds es -> TaggedFilterIds (e : es)++class PollFilters (es :: [*]) where+ openMultiFilter :: MultiFilter es -> Web3 (TaggedFilterIds es)+ checkMultiFilter :: TaggedFilterIds es -> Web3 [Field (WithChange es)]+ closeMultiFilter :: TaggedFilterIds es -> Web3 ()++instance PollFilters '[] where+ openMultiFilter _ = pure TaggedFilterNil+ checkMultiFilter _ = pure []+ closeMultiFilter _ = pure ()++instance forall e i ni es.+ ( DecodeEvent i ni e+ , PollFilters es+ , RecApplicative (WithChange es)+ , FoldRec (FilterChange e : WithChange es) (WithChange es)+ ) => PollFilters (e:es) where+ openMultiFilter (f :? fs) = do+ fId <- Eth.newFilter f+ fsIds <- openMultiFilter fs+ pure $ TaggedFilterCons (Tagged fId) fsIds++ checkMultiFilter (TaggedFilterCons (Tagged fId) fsIds) = do+ changes <- Eth.getFilterChanges fId+ filterChanges <- liftIO . mkFilterChanges @_ @_ @e $ changes+ filterChanges' <- checkMultiFilter @es fsIds+ pure $ map (CoRec . Identity) filterChanges <> map weakenCoRec filterChanges'++ closeMultiFilter (TaggedFilterCons (Tagged fId) fsIds) = do+ _ <- Eth.uninstallFilter fId+ closeMultiFilter fsIds+++-- | Polls a filter from the given filterId until the target toBlock is reached.+pollMultiFilter+ :: ( PollFilters es+ , RecApplicative (WithChange es)+ , AllAllSat '[HasLogIndex] (WithChange es)+ )+ => TaggedFilterIds es+ -> DefaultBlock+ -> MachineT Web3 k [Field (WithChange es)]+pollMultiFilter is = construct . pollPlan is+ where+ -- pollPlan :: TaggedFilterIds es -> DefaultBlock -> PlanT k [Field (Map (TyCon1 FilterChange) es)] Web3 ()+ pollPlan (fIds :: TaggedFilterIds es) end = do+ bn <- lift $ Eth.blockNumber+ if BlockWithNumber bn > end+ then do+ _ <- lift $ closeMultiFilter fIds+ stop+ else do+ liftIO $ threadDelay 1000000+ changes <- lift $ sortChanges <$> checkMultiFilter fIds+ yield changes+ pollPlan fIds end++--------------------------------------------------------------------------------+++multiEventNoFilter+ :: ( QueryAllLogs es+ , MapHandlers Web3 es (WithChange es)+ , AllAllSat '[HasLogIndex] (WithChange es)+ , RecApplicative (WithChange es)+ )+ => MultiFilter es+ -> Handlers es (ReaderT Change Web3 EventAction)+ -> Web3 (Async ())+multiEventNoFilter fltrs = forkWeb3 . multiEventNoFilter' fltrs++multiEventNoFilter'+ :: ( QueryAllLogs es+ , MapHandlers Web3 es (WithChange es)+ , AllAllSat '[HasLogIndex] (WithChange es)+ , RecApplicative (WithChange es)+ )+ => MultiFilter es+ -> Handlers es (ReaderT Change Web3 EventAction)+ -> Web3 ()+multiEventNoFilter' fltrs = multiEventManyNoFilter' fltrs 0+++multiEventManyNoFilter'+ :: ( QueryAllLogs es+ , MapHandlers Web3 es (WithChange es)+ , AllAllSat '[HasLogIndex] (WithChange es)+ , RecApplicative (WithChange es)+ )+ => MultiFilter es+ -> Integer+ -> Handlers es (ReaderT Change Web3 EventAction)+ -> Web3 ()+multiEventManyNoFilter' fltrs window handlers = do+ start <- mkBlockNumber $ minStartBlock fltrs+ let initState =+ MultiFilterStreamState { mfssCurrentBlock = start+ , mfssInitialMultiFilter = fltrs+ , mfssWindowSize = window+ }+ mLastProcessedFilterState <- reduceMultiEventStream (playMultiLogs initState) handlers+ case mLastProcessedFilterState of+ Nothing ->+ let pollingFilterState =+ MultiFilterStreamState { mfssCurrentBlock = start+ , mfssInitialMultiFilter = fltrs+ , mfssWindowSize = 0+ }+ in void $ reduceMultiEventStream (playNewMultiLogs pollingFilterState) handlers+ Just (act, lastBlock) -> do+ end <- mkBlockNumber . minEndBlock $ fltrs+ when (act /= TerminateEvent && lastBlock < end) $+ let pollingFilterState = MultiFilterStreamState { mfssCurrentBlock = lastBlock + 1+ , mfssInitialMultiFilter = fltrs+ , mfssWindowSize = 0+ }+ in void $ reduceMultiEventStream (playNewMultiLogs pollingFilterState) handlers++newMultiFilterStream+ :: MultiFilterStreamState es+ -> MachineT Web3 k (MultiFilter es)+newMultiFilterStream initialPlan = do+ unfoldPlan initialPlan $ \s -> do+ let end = minEndBlock . mfssInitialMultiFilter $ initialPlan+ filterPlan end s+ where+ filterPlan :: DefaultBlock -> MultiFilterStreamState es -> PlanT k (MultiFilter es) Web3 (MultiFilterStreamState es)+ filterPlan end initialState@MultiFilterStreamState{..} = do+ if BlockWithNumber mfssCurrentBlock > end+ then stop+ else do+ newestBlockNumber <- lift . pollTillBlockProgress $ mfssCurrentBlock+ let h :: forall e. Filter e -> Filter e+ h f = f { filterFromBlock = BlockWithNumber mfssCurrentBlock+ , filterToBlock = BlockWithNumber newestBlockNumber+ }+ yield (modifyMultiFilter h mfssInitialMultiFilter)+ filterPlan end initialState { mfssCurrentBlock = newestBlockNumber + 1 }++playNewMultiLogs+ :: forall es k.+ ( QueryAllLogs es+ , AllAllSat '[HasLogIndex] (WithChange es)+ , RecApplicative (WithChange es)+ )+ => MultiFilterStreamState es+ -> MachineT Web3 k [Field (WithChange es)]+playNewMultiLogs s = fmap sortChanges $+ newMultiFilterStream s+ ~> autoM queryAllLogs
+ src/Network/Ethereum/Contract/Event/SingleFilter.hs view
@@ -0,0 +1,256 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeFamilyDependencies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}++-- |+-- Module : Network.Ethereum.Contract.Event.SingleFilter+-- Copyright : FOAM team <http://foam.space> 2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : unportable+--+-- Simple contract event filter support.+--++module Network.Ethereum.Contract.Event.SingleFilter+ (+ event+ , event'+ , eventMany'+ , eventNoFilter+ , eventNoFilter'+ , eventManyNoFilter'+ ) where++import Control.Concurrent (threadDelay)+import Control.Concurrent.Async (Async)+import Control.Monad (forM, void, when)+import Control.Monad.IO.Class (MonadIO (..))+import Control.Monad.Trans.Class (lift)+import Control.Monad.Trans.Reader (ReaderT (..))+import Data.Machine (MachineT, asParts,+ autoM, await,+ construct, final,+ repeatedly, runT,+ unfoldPlan, (~>))+import Data.Machine.Plan (PlanT, stop, yield)+import Data.Maybe (catMaybes, listToMaybe)++import Data.Solidity.Event (DecodeEvent (..))+import qualified Network.Ethereum.Api.Eth as Eth+import Network.Ethereum.Api.Provider (Web3, forkWeb3)+import Network.Ethereum.Api.Types (Change (..),+ DefaultBlock (..),+ Filter (..), Quantity)+import Network.Ethereum.Contract.Event.Common++-- | Run 'event\'' one block at a time.+event :: DecodeEvent i ni e+ => Filter e+ -> (e -> ReaderT Change Web3 EventAction)+ -> Web3 (Async ())+event fltr = forkWeb3 . event' fltr++-- | Same as 'event', but does not immediately spawn a new thread.+event' :: DecodeEvent i ni e+ => Filter e+ -> (e -> ReaderT Change Web3 EventAction)+ -> Web3 ()+event' fltr = eventMany' fltr 0++-- | 'eventMany\'' take s a filter, a window size, and a handler.+--+-- It runs the handler over the results of 'eventLogs' results using+-- 'reduceEventStream'. If no 'TerminateEvent' action is thrown and+-- the toBlock is not yet reached, it then transitions to polling.+--+eventMany' :: DecodeEvent i ni e+ => Filter e+ -> Integer+ -> (e -> ReaderT Change Web3 EventAction)+ -> Web3 ()+eventMany' fltr window handler = do+ start <- mkBlockNumber $ filterFromBlock fltr+ let initState = FilterStreamState { fssCurrentBlock = start+ , fssInitialFilter = fltr+ , fssWindowSize = window+ }+ mLastProcessedFilterState <- reduceEventStream (playOldLogs initState) handler+ case mLastProcessedFilterState of+ Nothing -> startPolling fltr {filterFromBlock = BlockWithNumber start}+ Just (act, lastBlock) -> do+ end <- mkBlockNumber . filterToBlock $ fltr+ when (act /= TerminateEvent && lastBlock < end) $+ let pollingFromBlock = lastBlock + 1+ in startPolling fltr {filterFromBlock = BlockWithNumber pollingFromBlock}+ where+ startPolling fltr' = do+ filterId <- Eth.newFilter fltr'+ let pollTo = filterToBlock fltr'+ void $ reduceEventStream (pollFilter filterId pollTo) handler++-- | Effectively a mapM_ over the machine using the given handler.+reduceEventStream :: Monad m+ => MachineT m k [FilterChange a]+ -> (a -> ReaderT Change m EventAction)+ -> m (Maybe (EventAction, Quantity))+reduceEventStream filterChanges handler = fmap listToMaybe . runT $+ filterChanges+ ~> autoM (processChanges handler)+ ~> asParts+ ~> runWhile (\(act, _) -> act /= TerminateEvent)+ ~> final+ where+ runWhile p = repeatedly $ do+ v <- await+ if p v+ then yield v+ else yield v >> stop+ processChanges :: Monad m+ => (a -> ReaderT Change m EventAction)+ -> [FilterChange a]+ -> m [(EventAction, Quantity)]+ processChanges handler' changes = fmap catMaybes $+ forM changes $ \FilterChange{..} -> do+ act <- flip runReaderT filterChangeRawChange $+ handler' filterChangeEvent+ return ((,) act <$> changeBlockNumber filterChangeRawChange)++-- | 'playLogs' streams the 'filterStream' and calls eth_getLogs on these 'Filter' objects.+playOldLogs+ :: DecodeEvent i ni e+ => FilterStreamState e+ -> MachineT Web3 k [FilterChange e]+playOldLogs s = filterStream s+ ~> autoM Eth.getLogs+ ~> autoM (liftIO . mkFilterChanges)++-- | Polls a filter from the given filterId until the target toBlock is reached.+pollFilter :: forall i ni e k . DecodeEvent i ni e+ => Quantity+ -> DefaultBlock+ -> MachineT Web3 k [FilterChange e]+pollFilter i = construct . pollPlan i+ where+ pollPlan :: Quantity -> DefaultBlock -> PlanT k [FilterChange e] Web3 ()+ pollPlan fid end = do+ bn <- lift $ Eth.blockNumber+ if BlockWithNumber bn > end+ then do+ _ <- lift $ Eth.uninstallFilter fid+ stop+ else do+ liftIO $ threadDelay 1000000+ changes <- lift $ Eth.getFilterChanges fid >>= liftIO . mkFilterChanges+ yield $ changes+ pollPlan fid end+++-- | 'filterStream' is a machine which represents taking an initial filter+-- over a range of blocks b1, ... bn (where bn is possibly `Latest` or `Pending`,+-- but b1 is an actual block number), and making a stream of filter objects+-- which cover this filter in intervals of size `windowSize`. The machine+-- halts whenever the `fromBlock` of a spanning filter either (1) excedes then+-- initial filter's `toBlock` or (2) is greater than the chain head's block number.+filterStream :: FilterStreamState e+ -> MachineT Web3 k (Filter e)+filterStream initialPlan = unfoldPlan initialPlan filterPlan+ where+ filterPlan :: FilterStreamState e -> PlanT k (Filter e) Web3 (FilterStreamState e)+ filterPlan initialState@FilterStreamState{..} = do+ end <- lift . mkBlockNumber $ filterToBlock fssInitialFilter+ if fssCurrentBlock > end+ then stop+ else do+ let to' = min end $ fssCurrentBlock + fromInteger fssWindowSize+ filter' = fssInitialFilter { filterFromBlock = BlockWithNumber fssCurrentBlock+ , filterToBlock = BlockWithNumber to'+ }+ yield filter'+ filterPlan $ initialState { fssCurrentBlock = to' + 1 }++--------------------------------------------------------------------------------++-- | Run 'event\'' one block at a time.+eventNoFilter+ :: DecodeEvent i ni e+ => Filter e+ -> (e -> ReaderT Change Web3 EventAction)+ -> Web3 (Async ())+eventNoFilter fltr = forkWeb3 . event' fltr++-- | Same as 'event', but does not immediately spawn a new thread.+eventNoFilter'+ :: DecodeEvent i ni e+ => Filter e+ -> (e -> ReaderT Change Web3 EventAction)+ -> Web3 ()+eventNoFilter' fltr = eventManyNoFilter' fltr 0++eventManyNoFilter'+ :: DecodeEvent i ni e+ => Filter e+ -> Integer+ -> (e -> ReaderT Change Web3 EventAction)+ -> Web3 ()+eventManyNoFilter' fltr window handler = do+ start <- mkBlockNumber $ filterFromBlock fltr+ let initState = FilterStreamState { fssCurrentBlock = start+ , fssInitialFilter = fltr+ , fssWindowSize = window+ }+ mLastProcessedFilterState <- reduceEventStream (playOldLogs initState) handler+ case mLastProcessedFilterState of+ Nothing ->+ let pollingFilterState = FilterStreamState { fssCurrentBlock = start+ , fssInitialFilter = fltr+ , fssWindowSize = 1+ }++ in void $ reduceEventStream (playNewLogs pollingFilterState) handler+ Just (act, lastBlock) -> do+ end <- mkBlockNumber . filterToBlock $ fltr+ when (act /= TerminateEvent && lastBlock < end) $+ let pollingFilterState = FilterStreamState { fssCurrentBlock = lastBlock + 1+ , fssInitialFilter = fltr+ , fssWindowSize = 1+ }+ in void $ reduceEventStream (playNewLogs pollingFilterState) handler++-- | 'playLogs' streams the 'filterStream' and calls eth_getLogs on these 'Filter' objects.+playNewLogs+ :: DecodeEvent i ni e+ => FilterStreamState e+ -> MachineT Web3 k [FilterChange e]+playNewLogs s =+ newFilterStream s+ ~> autoM Eth.getLogs+ ~> autoM (liftIO . mkFilterChanges)++newFilterStream+ :: FilterStreamState e+ -> MachineT Web3 k (Filter e)+newFilterStream initialState = unfoldPlan initialState filterPlan+ where+ filterPlan :: FilterStreamState e -> PlanT k (Filter e) Web3 (FilterStreamState e)+ filterPlan s@FilterStreamState{..} = do+ if BlockWithNumber fssCurrentBlock > filterToBlock fssInitialFilter+ then stop+ else do+ newestBlockNumber <- lift . pollTillBlockProgress $ fssCurrentBlock+ let filter' = fssInitialFilter { filterFromBlock = BlockWithNumber fssCurrentBlock+ , filterToBlock = BlockWithNumber newestBlockNumber+ }+ yield filter'+ filterPlan $ s { fssCurrentBlock = newestBlockNumber + 1 }
src/Network/Ethereum/Contract/Method.hs view
@@ -1,5 +1,3 @@-{-# LANGUAGE ScopedTypeVariables #-}- -- | -- Module : Network.Ethereum.Contract.Method -- Copyright : Alexander Krupenkin 2016-2018@@ -12,60 +10,24 @@ -- Ethereum contract method support. -- -module Network.Ethereum.Contract.Method (- Method(..)- , call- , sendTx- ) where--import Control.Monad.Catch (throwM)-import Data.Monoid ((<>))-import Data.Proxy (Proxy (..))+module Network.Ethereum.Contract.Method where -import Network.Ethereum.ABI.Class (ABIGet, ABIPut, ABIType (..))-import Network.Ethereum.ABI.Codec (decode, encode)-import Network.Ethereum.ABI.Prim.Bytes (Bytes)-import qualified Network.Ethereum.Web3.Eth as Eth-import Network.Ethereum.Web3.Provider (Web3, Web3Error (ParserFail))-import Network.Ethereum.Web3.Types (Call (callData), DefaultBlock,- Hash)+import Data.Proxy (Proxy)+import Data.Solidity.Abi (AbiPut, AbiType (..))+import Data.Solidity.Abi.Generic ()+import Data.Solidity.Prim.Bytes (Bytes) -class ABIPut a => Method a where- selector :: Proxy a -> Bytes+-- | Smart contract method encoding+class AbiPut a => Method a where+ -- | Solidity function selector+ -- https://solidity.readthedocs.io/en/latest/abi-spec.html#function-selector-and-argument-encoding+ selector :: Proxy a -> Bytes -instance ABIType () where- isDynamic _ = False+instance AbiType () where+ isDynamic _ = False -instance ABIPut ()+instance AbiPut () --- | Send transaction without method selection+-- | Fallback contract method instance Method () where- selector = mempty---- | 'sendTx' is used to submit a state changing transaction.-sendTx :: Method a- => Call- -- ^ Call configuration- -> a- -- ^ method data- -> Web3 Hash-sendTx call' (dat :: a) =- let sel = selector (Proxy :: Proxy a)- in Eth.sendTransaction (call' { callData = Just $ sel <> encode dat })---- | 'call' is used to call contract methods that have no state changing effects.-call :: (Method a, ABIGet b)- => Call- -- ^ Call configuration- -> DefaultBlock- -- ^ State mode for constant call (latest or pending)- -> a- -- ^ Method data- -> Web3 b- -- ^ 'Web3' wrapped result-call call' mode (dat :: a) = do- let sel = selector (Proxy :: Proxy a)- res <- Eth.call (call' { callData = Just $ sel <> encode dat }) mode- case decode res of- Left e -> throwM $ ParserFail $ "Unable to parse response: " ++ e- Right x -> return x+ selector _ = mempty
src/Network/Ethereum/Contract/TH.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TemplateHaskell #-}@@ -17,7 +18,7 @@ -- The Application Binary Interface is the standard way to interact -- with contracts in the Ethereum ecosystem. It can be described by -- specially JSON file, like @ERC20.json@. This module use TemplateHaskell--- for generation described in ABI contract methods and events. Helper+-- for generation described in Abi contract methods and events. Helper -- functions and instances inserted in haskell module and can be used in -- another modules or in place. --@@ -35,10 +36,18 @@ -- Full code example available in examples folder. -- -module Network.Ethereum.Contract.TH (abi, abiFrom) where+module Network.Ethereum.Contract.TH+ (+ -- * The contract quasiquoters+ abi+ , abiFrom+ ) where +import Control.Applicative ((<|>)) import Control.Monad (replicateM, (<=<))-import Data.Aeson (eitherDecode)+import qualified Data.Aeson as Aeson (encode)+import Data.ByteArray (convert)+import qualified Data.Char as Char import Data.Default (Default (..)) import Data.List (group, sort, uncons) import Data.Monoid ((<>))@@ -47,39 +56,43 @@ import qualified Data.Text as T import qualified Data.Text.Lazy as LT import qualified Data.Text.Lazy.Encoding as LT+import Data.Tuple.OneTuple (only) import Generics.SOP (Generic) import qualified GHC.Generics as GHC (Generic) import Language.Haskell.TH import Language.Haskell.TH.Quote+import Lens.Micro ((^?))+import Lens.Micro.Aeson (key, _JSON, _String) +import Data.Solidity.Abi (AbiGet, AbiPut, AbiType (..))+import Data.Solidity.Event (IndexedEvent (..))+import Data.Solidity.Prim (Address, Bytes, BytesN, IntN,+ ListN, UIntN) import Data.String.Extra (toLowerFirst, toUpperFirst)-import Network.Ethereum.ABI.Class (ABIGet, ABIPut, ABIType (..))-import Network.Ethereum.ABI.Event (IndexedEvent (..))-import Network.Ethereum.ABI.Json (ContractABI (..),+import Language.Solidity.Abi (ContractAbi (..), Declaration (..), EventArg (..), FunctionArg (..), SolidityType (..), eventId, methodId, parseSolidityType)-import Network.Ethereum.ABI.Prim (Address, Bytes, BytesN, IntN,- ListN, Singleton (..), UIntN)-import Network.Ethereum.Contract.Method (Method (..), call, sendTx)-import Network.Ethereum.Web3.Provider (Web3)-import Network.Ethereum.Web3.Types (Call, DefaultBlock (..),- Filter (..), Hash)+import Network.Ethereum.Account.Class (Account (..))+import Network.Ethereum.Api.Types (DefaultBlock (..),+ Filter (..), TxReceipt)+import qualified Network.Ethereum.Contract as Contract (Contract (..))+import Network.Ethereum.Contract.Method (Method (..))+import Network.JsonRpc.TinyClient (JsonRpc) --- | Read contract ABI from file+-- | Read contract Abi from file abiFrom :: QuasiQuoter abiFrom = quoteFile abi --- | QQ reader for contract ABI+-- | QQ reader for contract Abi abi :: QuasiQuoter abi = QuasiQuoter- { quoteDec = quoteAbiDec- , quoteExp = quoteAbiExp- , quotePat = undefined- , quoteType = undefined- }+ { quoteDec = quoteAbiDec+ , quoteExp = quoteAbiExp+ , quotePat = undefined+ , quoteType = undefined } -- | Instance declaration with empty context instanceD' :: Name -> TypeQ -> [DecQ] -> DecQ@@ -88,14 +101,14 @@ -- | Simple data type declaration with one constructor dataD' :: Name -> ConQ -> [Name] -> DecQ-dataD' name rec derive =- dataD (cxt []) name [] Nothing [rec] [derivClause Nothing (conT <$> derive)]+dataD' name rec' derive =+ dataD (cxt []) name [] Nothing [rec'] [derivClause Nothing (conT <$> derive)] -- | Simple function declaration funD' :: Name -> [PatQ] -> ExpQ -> DecQ funD' name p f = funD name [clause p (normalB f) []] --- | ABI and Haskell types association+-- | Abi and Haskell types association toHSType :: SolidityType -> TypeQ toHSType s = case s of SolidityBool -> conT ''Bool@@ -112,9 +125,9 @@ expandVector :: [Int] -> SolidityType -> TypeQ expandVector ns a = case uncons ns of Just (n, rest) ->- if length rest == 0- then (conT ''ListN) `appT` numLit n `appT` toHSType a- else (conT ''ListN) `appT` numLit n `appT` expandVector rest a+ if null rest+ then conT ''ListN `appT` numLit n `appT` toHSType a+ else conT ''ListN `appT` numLit n `appT` expandVector rest a _ -> error $ "Impossible Nothing branch in `expandVector`: " ++ show ns ++ " " ++ show a typeQ :: Text -> TypeQ@@ -139,44 +152,47 @@ -- ^ Results -> DecsQ funWrapper c name dname args result = do- a : _ : vars <- replicateM (length args + 2) (newName "t")- let params = appsE $ conE dname : fmap varE vars+ vars <- replicateM (length args) (newName "t")+ a <- varT <$> newName "a"+ t <- varT <$> newName "t"+ m <- varT <$> newName "m" - sequence $ if c- then- [ sigD name $ [t|$(arrowing $ [t|Call|] : inputT ++ [outputT])|]- , funD' name (varP <$> a : vars) $- case result of- Just [_] -> [|unSingleton <$> call $(varE a) Latest $(params)|]- _ -> [|call $(varE a) Latest $(params)|]- ] - else- [ sigD name $ [t|$(arrowing $ [t|Call|] : inputT ++ [[t|Web3 Hash|]])|]- , funD' name (varP <$> a : vars) $- [|sendTx $(varE a) $(params)|] ]+ let params = appsE $ conE dname : fmap varE vars+ inputT = fmap (typeQ . funArgType) args+ outputT = case result of+ Nothing -> [t|$t $m ()|]+ Just [x] -> [t|$t $m $(typeQ $ funArgType x)|]+ Just xs -> let outs = fmap (typeQ . funArgType) xs+ in [t|$t $m $(foldl appT (tupleT (length xs)) outs)|]++ sequence [+ sigD name $ [t|+ (JsonRpc $m, Account $a $t, Functor ($t $m)) =>+ $(arrowing $ inputT ++ [if c then outputT else [t|$t $m TxReceipt|]])+ |]+ , if c+ then funD' name (varP <$> vars) $ case result of+ Just [_] -> [|only <$> call $(params)|]+ _ -> [|call $(params)|]+ else funD' name (varP <$> vars) $ [|send $(params)|]+ ] where arrowing [] = error "Impossible branch call" arrowing [x] = x arrowing (x : xs) = [t|$x -> $(arrowing xs)|]- inputT = fmap (typeQ . funArgType) args- outputT = case result of- Nothing -> [t|Web3 ()|]- Just [x] -> [t|Web3 $(typeQ $ funArgType x)|]- Just xs -> let outs = fmap (typeQ . funArgType) xs- in [t|Web3 $(foldl appT (tupleT (length xs)) outs)|] mkDecl :: Declaration -> DecsQ -mkDecl ev@(DEvent name inputs anonymous) = sequence+mkDecl ev@(DEvent uncheckedName inputs anonymous) = sequence [ dataD' indexedName (normalC indexedName (map (toBang <=< tag) indexedArgs)) derivingD , instanceD' indexedName (conT ''Generic) []- , instanceD' indexedName (conT ''ABIType) [funD' 'isDynamic [] [|const False|]]- , instanceD' indexedName (conT ''ABIGet) []+ , instanceD' indexedName (conT ''AbiType) [funD' 'isDynamic [] [|const False|]]+ , instanceD' indexedName (conT ''AbiGet) [] , dataD' nonIndexedName (normalC nonIndexedName (map (toBang <=< tag) nonIndexedArgs)) derivingD , instanceD' nonIndexedName (conT ''Generic) []- , instanceD' nonIndexedName (conT ''ABIType) [funD' 'isDynamic [] [|const False|]]- , instanceD' nonIndexedName (conT ''ABIGet) []+ , instanceD' nonIndexedName (conT ''AbiType) [funD' 'isDynamic [] [|const False|]]+ , instanceD' nonIndexedName (conT ''AbiGet) [] , dataD' allName (recC allName (map (\(n, a) -> ((\(b,t) -> return (n,b,t)) <=< toBang <=< typeQ $ a)) allArgs)) derivingD , instanceD' allName (conT ''Generic) [] , instanceD (cxt [])@@ -187,6 +203,7 @@ [funD' 'def [] [|Filter Nothing Latest Latest $ Just topics|] ] ] where+ name = if Char.toLower (T.head uncheckedName) == Char.toUpper (T.head uncheckedName) then "EvT" <> uncheckedName else uncheckedName topics = [Just (T.unpack $ eventId ev)] <> replicate (length indexedArgs) Nothing toBang ty = bangType (bang sourceNoUnpack sourceStrict) (return ty) tag (n, ty) = AppT (AppT (ConT ''Tagged) (LitT $ NumTyLit n)) <$> typeQ ty@@ -199,16 +216,17 @@ allName = mkName $ toUpperFirst (T.unpack name) derivingD = [''Show, ''Eq, ''Ord, ''GHC.Generic] +-- TODO change this type name also -- | Method delcarations maker mkDecl fun@(DFunction name constant inputs outputs) = (++) <$> funWrapper constant fnName dataName inputs outputs <*> sequence [ dataD' dataName (normalC dataName bangInput) derivingD , instanceD' dataName (conT ''Generic) []- , instanceD' dataName (conT ''ABIType)+ , instanceD' dataName (conT ''AbiType) [funD' 'isDynamic [] [|const False|]]- , instanceD' dataName (conT ''ABIPut) []- , instanceD' dataName (conT ''ABIGet) []+ , instanceD' dataName (conT ''AbiPut) []+ , instanceD' dataName (conT ''AbiGet) [] , instanceD' dataName (conT ''Method) [funD' 'selector [] [|const mIdent|]] ]@@ -220,6 +238,28 @@ mkDecl _ = return [] +mkContractDecl :: Text -> Text -> Text -> Declaration -> DecsQ+mkContractDecl name a b (DConstructor inputs) = sequence+ [ dataD' dataName (normalC dataName bangInput) derivingD+ , instanceD' dataName (conT ''Generic) []+ , instanceD' dataName (conT ''AbiType)+ [funD' 'isDynamic [] [|const False|]]+ , instanceD' dataName (conT ''AbiPut) []+ , instanceD' dataName (conT ''Method)+ [funD' 'selector [] [|convert . Contract.bytecode|]]+ , instanceD' dataName (conT ''Contract.Contract)+ [ funD' 'Contract.abi [] [|const abiString|]+ , funD' 'Contract.bytecode [] [|const bytecodeString|]+ ]+ ]+ where abiString = T.unpack a+ bytecodeString = T.unpack b+ dataName = mkName (toUpperFirst (T.unpack $ name <> "Contract"))+ bangInput = fmap funBangType inputs+ derivingD = [''Show, ''Eq, ''Ord, ''GHC.Generic]++mkContractDecl _ _ _ _ = return []+ -- | this function gives appropriate names for the accessors in the following way -- | argName -> evArgName -- | arg_name -> evArg_name@@ -231,15 +271,15 @@ prefixStr = toLowerFirst . T.unpack $ prefix go :: Int -> [(Text, Text)] -> [(Name, Text)] go _ [] = []- go i ((h, ty) : tail') = if T.null h- then (mkName $ prefixStr ++ show i, ty) : go (i + 1) tail'- else (mkName . (++ "_") . (++) prefixStr . toUpperFirst . T.unpack $ h, ty) : go (i + 1) tail'+ go i ((h, ty) : tail')+ | T.null h = (mkName $ prefixStr ++ show i, ty) : go (i + 1) tail'+ | otherwise = (mkName . (++ "_") . (++) prefixStr . toUpperFirst . T.unpack $ h, ty) : go (i + 1) tail' escape :: [Declaration] -> [Declaration] escape = escapeEqualNames . fmap escapeReservedNames escapeEqualNames :: [Declaration] -> [Declaration]-escapeEqualNames = concat . fmap go . group . sort+escapeEqualNames = concatMap go . group . sort where go [] = [] go (x : xs) = x : zipWith appendToName xs hats hats = [T.replicate n "'" | n <- [1..]]@@ -262,20 +302,38 @@ , "infix", "infixl", "infixr" , "let", "in", "mdo", "module" , "newtype", "proc", "qualified"- , "rec", "type", "where"]+ , "rec", "type", "where"+ ] --- | ABI to declarations converter+constructorSpec :: String -> Maybe (Text, Text, Text, Declaration)+constructorSpec str = do+ name <- str ^? key "contractName" . _String+ abiValue <- str ^? key "abi"+ bytecode <- str ^? key "bytecode" . _String+ decl <- filter isContructor . unAbi <$> str ^? key "abi" . _JSON+ return (name, jsonEncode abiValue, bytecode, toConstructor decl)+ where+ jsonEncode = LT.toStrict . LT.decodeUtf8 . Aeson.encode+ isContructor (DConstructor _) = True+ isContructor _ = False+ toConstructor [] = DConstructor []+ toConstructor [a] = a+ toConstructor _ = error "Broken ABI: more that one constructor"++-- | Abi to declarations converter quoteAbiDec :: String -> DecsQ-quoteAbiDec abi_string =- case eitherDecode abi_lbs of- Left e -> fail $ "Error: " ++ show e- Right (ContractABI a) -> concat <$> mapM mkDecl (escape a)- where abi_lbs = LT.encodeUtf8 (LT.pack abi_string)+quoteAbiDec str =+ case str ^? _JSON <|> str ^? key "abi" . _JSON of+ Nothing -> fail "Unable to decode contract ABI"+ Just (ContractAbi decs) -> do+ funEvDecs <- concat <$> mapM mkDecl (escape decs)+ case constructorSpec str of+ Nothing -> return funEvDecs+ Just (a, b, c, d) -> (funEvDecs ++) <$> mkContractDecl a b c d --- | ABI information string+-- | Abi information string quoteAbiExp :: String -> ExpQ-quoteAbiExp abi_string = stringE $- case eitherDecode abi_lbs of- Left e -> "Error: " ++ show e- Right a -> show (a :: ContractABI)- where abi_lbs = LT.encodeUtf8 (LT.pack abi_string)+quoteAbiExp str =+ case str ^? _JSON <|> str ^? key "abi" . _JSON of+ Nothing -> fail "Unable to decode contract ABI"+ Just a@(ContractAbi _) -> stringE (show a)
+ src/Network/Ethereum/Ens.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}++-- |+-- Module : Network.Ethereum.Ens+-- Copyright : Alexander Krupenkin 2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : unportable+--+-- ENS offers a secure & decentralised way to address resources both on+-- and off the blockchain using simple, human-readable names.+--+-- This module provide basic ENS resolvers.+--++module Network.Ethereum.Ens where++import Crypto.Hash (Digest, Keccak_256, hash)+import Data.ByteArray (convert, zero)+import Data.ByteArray.Sized (unsafeFromByteArrayAccess)+import Data.ByteString (ByteString)+import Data.ByteString.Char8 (split)+import Data.Monoid ((<>))+import Lens.Micro ((.~))++import Data.Solidity.Prim (Address, BytesN)+import Network.Ethereum.Account.Class (Account)+import Network.Ethereum.Account.Internal (AccountT, to, withParam)+import qualified Network.Ethereum.Ens.PublicResolver as Resolver+import qualified Network.Ethereum.Ens.Registry as Reg+import Network.JsonRpc.TinyClient (JsonRpc)++-- | Namehash algorithm+-- http://docs.ens.domains/en/latest/implementers.html#algorithm+namehash :: ByteString+ -- ^ Domain name+ -> BytesN 32+ -- ^ Associated ENS node+namehash =+ unsafeFromByteArrayAccess . foldr algo (zero 32) . split '.'+ where+ algo a b = sha3 (b <> sha3 a)+ sha3 :: ByteString -> ByteString+ sha3 bs = convert (hash bs :: Digest Keccak_256)++-- | Get address of ENS domain+resolve :: (JsonRpc m, Account p (AccountT p))+ => ByteString+ -- ^ Domain name+ -> AccountT p m Address+ -- ^ Associated address+resolve name = do+ r <- ensRegistry $ Reg.resolver node+ withParam (to .~ r) $ Resolver.addr node+ where+ node = namehash name+ ensRegistry = withParam $ to .~ "0x314159265dD8dbb310642f98f50C066173C1259b"
+ src/Network/Ethereum/Ens/PublicResolver.hs view
@@ -0,0 +1,25 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}++-- |+-- Module : Network.Ethereum.Ens.PublicResolver+-- Copyright : Alexander Krupenkin 2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : unportable+--+-- Ethereum Name System public resolver smart contract.+--++module Network.Ethereum.Ens.PublicResolver where++import Network.Ethereum.Contract.TH++[abi|[{"constant":true,"inputs":[{"name":"interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"node","type":"bytes32"},{"name":"contentTypes","type":"uint256"}],"name":"ABI","outputs":[{"name":"contentType","type":"uint256"},{"name":"data","type":"bytes"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"node","type":"bytes32"},{"name":"x","type":"bytes32"},{"name":"y","type":"bytes32"}],"name":"setPubkey","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"node","type":"bytes32"}],"name":"content","outputs":[{"name":"ret","type":"bytes32"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"node","type":"bytes32"}],"name":"addr","outputs":[{"name":"ret","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"node","type":"bytes32"},{"name":"contentType","type":"uint256"},{"name":"data","type":"bytes"}],"name":"setABI","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"node","type":"bytes32"}],"name":"name","outputs":[{"name":"ret","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"node","type":"bytes32"},{"name":"name","type":"string"}],"name":"setName","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"node","type":"bytes32"},{"name":"hash","type":"bytes32"}],"name":"setContent","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"node","type":"bytes32"}],"name":"pubkey","outputs":[{"name":"x","type":"bytes32"},{"name":"y","type":"bytes32"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"node","type":"bytes32"},{"name":"addr","type":"address"}],"name":"setAddr","outputs":[],"payable":false,"type":"function"},{"inputs":[{"name":"ensAddr","type":"address"}],"payable":false,"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"node","type":"bytes32"},{"indexed":false,"name":"a","type":"address"}],"name":"AddrChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"node","type":"bytes32"},{"indexed":false,"name":"hash","type":"bytes32"}],"name":"ContentChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"node","type":"bytes32"},{"indexed":false,"name":"name","type":"string"}],"name":"NameChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"node","type":"bytes32"},{"indexed":true,"name":"contentType","type":"uint256"}],"name":"ABIChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"node","type":"bytes32"},{"indexed":false,"name":"x","type":"bytes32"},{"indexed":false,"name":"y","type":"bytes32"}],"name":"PubkeyChanged","type":"event"}]|]
+ src/Network/Ethereum/Ens/Registry.hs view
@@ -0,0 +1,25 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}++-- |+-- Module : Network.Ethereum.Ens.Registry+-- Copyright : Alexander Krupenkin 2018+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : unportable+--+-- Ethereum Name System registry smart contract.+--++module Network.Ethereum.Ens.Registry where++import Network.Ethereum.Contract.TH++[abi|[{"constant":true,"inputs":[{"name":"node","type":"bytes32"}],"name":"resolver","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"node","type":"bytes32"}],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"node","type":"bytes32"},{"name":"label","type":"bytes32"},{"name":"owner","type":"address"}],"name":"setSubnodeOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"node","type":"bytes32"},{"name":"ttl","type":"uint64"}],"name":"setTTL","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"node","type":"bytes32"}],"name":"ttl","outputs":[{"name":"","type":"uint64"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"node","type":"bytes32"},{"name":"resolver","type":"address"}],"name":"setResolver","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"node","type":"bytes32"},{"name":"owner","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"node","type":"bytes32"},{"indexed":false,"name":"owner","type":"address"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"node","type":"bytes32"},{"indexed":true,"name":"label","type":"bytes32"},{"indexed":false,"name":"owner","type":"address"}],"name":"NewOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"node","type":"bytes32"},{"indexed":false,"name":"resolver","type":"address"}],"name":"NewResolver","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"node","type":"bytes32"},{"indexed":false,"name":"ttl","type":"uint64"}],"name":"NewTTL","type":"event"}]|]
src/Network/Ethereum/Unit.hs view
@@ -47,19 +47,22 @@ -- @ -- -module Network.Ethereum.Unit (- Unit(..)- , UnitSpec(..)- , Wei- , Babbage- , Lovelace- , Shannon- , Szabo- , Finney- , Ether- , KEther- ) where+module Network.Ethereum.Unit+ (+ -- * The @Unit@ type class+ Unit(..) + -- * Ethereum value metrics+ , Wei+ , Babbage+ , Lovelace+ , Shannon+ , Szabo+ , Finney+ , Ether+ , KEther+ ) where+ import Data.Proxy (Proxy (..)) import Data.Text.Lazy (Text, unpack) import GHC.Generics (Generic)@@ -71,13 +74,10 @@ -- | Ethereum value unit class (Read a, Show a, UnitSpec a, Fractional a) => Unit a where -- | Make a value from integer wei- fromWei :: Integer -> a+ fromWei :: Integral b => b -> a+ -- | Convert a value to integer wei- toWei :: a -> Integer- -- | Conversion beween two values- convert :: Unit b => a -> b- {-# INLINE convert #-}- convert = fromWei . toWei+ toWei :: Integral b => a -> b -- | Unit specification class UnitSpec a where@@ -92,8 +92,8 @@ mkValue = MkValue . round . (* divider (Proxy :: Proxy a)) instance UnitSpec a => Unit (Value a) where- fromWei = MkValue- toWei = unValue+ fromWei = MkValue . toInteger+ toWei = fromInteger . unValue instance UnitSpec a => UnitSpec (Value a) where divider = const $ divider (Proxy :: Proxy a)
src/Network/Ethereum/Web3.hs view
@@ -17,33 +17,28 @@ -- Web3 Haskell library currently use JSON-RPC over HTTP to access node functionality. -- -module Network.Ethereum.Web3 (-- -- ** Monad as base of any Ethereum node communication- Web3- , runWeb3-- -- ** Basic transaction sending- , sendTx- , Call(..)+module Network.Ethereum.Web3+ (+ -- * Base monad for any Ethereum node communication+ Web3+ , runWeb3 - -- ** Basic event listening- , EventAction(..)- , event- , event'+ -- * Basic transaction sending+ , module Account - -- ** Primitive data types- , module Network.Ethereum.ABI.Prim+ -- * Basic event listening+ , EventAction(..)+ , event - -- ** Metric unit system- , module Network.Ethereum.Unit+ -- * Primitive data types+ , module Prim - ) where+ -- * Metric unit system+ , module Unit+ ) where -import Network.Ethereum.ABI.Prim-import Network.Ethereum.Contract.Event (EventAction (..), event,- event')-import Network.Ethereum.Contract.Method (sendTx)-import Network.Ethereum.Unit-import Network.Ethereum.Web3.Provider (Web3, runWeb3)-import Network.Ethereum.Web3.Types (Call (..))+import Data.Solidity.Prim as Prim+import Network.Ethereum.Account as Account+import Network.Ethereum.Api.Provider (Web3, runWeb3)+import Network.Ethereum.Contract.Event (EventAction (..), event)+import Network.Ethereum.Unit as Unit
− src/Network/Ethereum/Web3/Eth.hs
@@ -1,250 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE OverloadedStrings #-}---- |--- Module : Network.Ethereum.Web3.Eth--- Copyright : Alexander Krupenkin 2016--- License : BSD3------ Maintainer : mail@akru.me--- Stability : experimental--- Portability : unknown------ Ethereum node JSON-RPC API methods with `eth_` prefix.-----module Network.Ethereum.Web3.Eth where--import Data.Text (Text)-import Network.Ethereum.ABI.Prim.Address (Address)-import Network.Ethereum.ABI.Prim.Bytes (Bytes, BytesN)-import Network.Ethereum.Web3.Provider (Web3)-import Network.Ethereum.Web3.Types (Block, Call, Change,- DefaultBlock, Filter, Hash,- Quantity, SyncingState,- Transaction, TxReceipt)-import Network.JsonRpc.TinyClient (remote)---- | Returns the current ethereum protocol version.-protocolVersion :: Web3 Text-{-# INLINE protocolVersion #-}-protocolVersion = remote "eth_protocolVersion"---- | Returns an object with data about the sync status or false.-syncing :: Web3 SyncingState-{-# INLINE syncing #-}-syncing = remote "eth_syncing"---- | Returns the client coinbase address.-coinbase :: Web3 Address-{-# INLINE coinbase #-}-coinbase = remote "eth_coinbase"---- | Returns true if client is actively mining new blocks.-mining :: Web3 Bool-{-# INLINE mining #-}-mining = remote "eth_mining"---- | Returns the number of hashes per second that the node is mining with.-hashrate :: Web3 Quantity-{-# INLINE hashrate #-}-hashrate = remote "eth_hashrate"---- | Returns the value from a storage position at a given address.-getStorageAt :: Address -> Quantity -> DefaultBlock -> Web3 (BytesN 32)-{-# INLINE getStorageAt #-}-getStorageAt = remote "eth_getStorageAt"---- | Returns the number of transactions sent from an address.-getTransactionCount :: Address -> DefaultBlock -> Web3 Quantity-{-# INLINE getTransactionCount #-}-getTransactionCount = remote "eth_getTransactionCount"---- | Returns the number of transactions in a block from a block matching the given block hash.-getBlockTransactionCountByHash :: Hash -> Web3 Quantity-{-# INLINE getBlockTransactionCountByHash #-}-getBlockTransactionCountByHash = remote "eth_getBlockTransactionCountByHash"---- | Returns the number of transactions in a block matching the--- given block number.-getBlockTransactionCountByNumber :: Quantity -> Web3 Quantity-{-# INLINE getBlockTransactionCountByNumber #-}-getBlockTransactionCountByNumber = remote "eth_getBlockTransactionCountByNumber"---- | Returns the number of uncles in a block from a block matching the given--- block hash.-getUncleCountByBlockHash :: Hash -> Web3 Quantity-{-# INLINE getUncleCountByBlockHash #-}-getUncleCountByBlockHash = remote "eth_getUncleCountByBlockHash"---- | Returns the number of uncles in a block from a block matching the given--- block number.-getUncleCountByBlockNumber :: Quantity -> Web3 Quantity-{-# INLINE getUncleCountByBlockNumber #-}-getUncleCountByBlockNumber = remote "eth_getUncleCountByBlockNumber"---- | Returns code at a given address.-getCode :: Address -> DefaultBlock -> Web3 Bytes-{-# INLINE getCode #-}-getCode = remote "eth_getCode"---- | Returns an Ethereum specific signature with:--- sign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))).-sign :: Address -> Bytes -> Web3 Bytes-{-# INLINE sign #-}-sign = remote "eth_sign"---- | Creates new message call transaction or a contract creation,--- if the data field contains code.-sendTransaction :: Call -> Web3 Hash-{-# INLINE sendTransaction #-}-sendTransaction = remote "eth_sendTransaction"---- | Creates new message call transaction or a contract creation for signed--- transactions.-sendRawTransaction :: Bytes -> Web3 Hash-{-# INLINE sendRawTransaction #-}-sendRawTransaction = remote "eth_sendRawTransaction"---- | Returns the balance of the account of given address.-getBalance :: Address -> DefaultBlock -> Web3 Quantity-{-# INLINE getBalance #-}-getBalance = remote "eth_getBalance"---- | Creates a filter object, based on filter options, to notify when the--- state changes (logs). To check if the state has changed, call--- 'getFilterChanges'.-newFilter :: Filter e -> Web3 Quantity-{-# INLINE newFilter #-}-newFilter = remote "eth_newFilter"---- | Polling method for a filter, which returns an array of logs which--- occurred since last poll.-getFilterChanges :: Quantity -> Web3 [Change]-{-# INLINE getFilterChanges #-}-getFilterChanges = remote "eth_getFilterChanges"---- | Uninstalls a filter with given id.--- Should always be called when watch is no longer needed.-uninstallFilter :: Quantity -> Web3 Bool-{-# INLINE uninstallFilter #-}-uninstallFilter = remote "eth_uninstallFilter"---- | Returns an array of all logs matching a given filter object.-getLogs :: Filter e -> Web3 [Change]-{-# INLINE getLogs #-}-getLogs = remote "eth_getLogs"---- | Executes a new message call immediately without creating a--- transaction on the block chain.-call :: Call -> DefaultBlock -> Web3 Bytes-{-# INLINE call #-}-call = remote "eth_call"---- | Makes a call or transaction, which won't be added to the blockchain and--- returns the used gas, which can be used for estimating the used gas.-estimateGas :: Call -> Web3 Quantity-{-# INLINE estimateGas #-}-estimateGas = remote "eth_estimateGas"---- | Returns information about a block by hash.-getBlockByHash :: Hash -> Web3 Block-{-# INLINE getBlockByHash #-}-getBlockByHash = flip (remote "eth_getBlockByHash") True---- | Returns information about a block by block number.-getBlockByNumber :: Quantity -> Web3 Block-{-# INLINE getBlockByNumber #-}-getBlockByNumber = flip (remote "eth_getBlockByNumber") True---- | Returns the information about a transaction requested by transaction hash.-getTransactionByHash :: Hash -> Web3 (Maybe Transaction)-{-# INLINE getTransactionByHash #-}-getTransactionByHash = remote "eth_getTransactionByHash"---- | Returns information about a transaction by block hash and transaction index position.-getTransactionByBlockHashAndIndex :: Hash -> Quantity -> Web3 (Maybe Transaction)-{-# INLINE getTransactionByBlockHashAndIndex #-}-getTransactionByBlockHashAndIndex = remote "eth_getTransactionByBlockHashAndIndex"---- | Returns information about a transaction by block number and transaction--- index position.-getTransactionByBlockNumberAndIndex :: DefaultBlock -> Quantity -> Web3 (Maybe Transaction)-{-# INLINE getTransactionByBlockNumberAndIndex #-}-getTransactionByBlockNumberAndIndex = remote "eth_getTransactionByBlockNumberAndIndex"---- | Returns the receipt of a transaction by transaction hash.-getTransactionReceipt :: Hash -> Web3 (Maybe TxReceipt)-{-# INLINE getTransactionReceipt #-}-getTransactionReceipt = remote "eth_getTransactionReceipt"---- | Returns a list of addresses owned by client.-accounts :: Web3 [Address]-{-# INLINE accounts #-}-accounts = remote "eth_accounts"---- | Creates a filter in the node, to notify when a new block arrives.-newBlockFilter :: Web3 Quantity-{-# INLINE newBlockFilter #-}-newBlockFilter = remote "eth_newBlockFilter"---- | Polling method for a block filter, which returns an array of block hashes--- occurred since last poll.-getBlockFilterChanges :: Quantity -> Web3 [Hash]-{-# INLINE getBlockFilterChanges #-}-getBlockFilterChanges = remote "eth_getFilterChanges"---- | Returns the number of most recent block.-blockNumber :: Web3 Quantity-{-# INLINE blockNumber #-}-blockNumber = remote "eth_blockNumber"---- | Returns the current price per gas in wei.-gasPrice :: Web3 Quantity-{-# INLINE gasPrice #-}-gasPrice = remote "eth_gasPrice"---- | Returns information about a uncle of a block by hash and uncle index--- position.-getUncleByBlockHashAndIndex :: Hash -> Quantity -> Web3 Block-{-# INLINE getUncleByBlockHashAndIndex #-}-getUncleByBlockHashAndIndex = remote "eth_getUncleByBlockHashAndIndex"---- | Returns information about a uncle of a block by number and uncle index--- position.-getUncleByBlockNumberAndIndex :: DefaultBlock -> Quantity -> Web3 Block-{-# INLINE getUncleByBlockNumberAndIndex #-}-getUncleByBlockNumberAndIndex = remote "eth_getUncleByBlockNumberAndIndex"---- | Creates a filter in the node, to notify when new pending transactions arrive. To check if the state has changed, call getFilterChanges. Returns a FilterId.-newPendingTransactionFilter :: Web3 Quantity-{-# INLINE newPendingTransactionFilter #-}-newPendingTransactionFilter = remote "eth_newPendingTransactionFilter"---- | Returns an array of all logs matching filter with given id.-getFilterLogs :: Quantity -> Web3 [Change]-{-# INLINE getFilterLogs #-}-getFilterLogs = remote "eth_getFilterLogs"---- | Returns the hash of the current block, the seedHash, and the boundary--- condition to be met ("target").-getWork :: Web3 [Bytes]-{-# INLINE getWork #-}-getWork = remote "eth_getWork"---- | Used for submitting a proof-of-work solution.--- Parameters:--- 1. DATA, 8 Bytes - The nonce found (64 bits)--- 2. DATA, 32 Bytes - The header's pow-hash (256 bits)--- 3. DATA, 32 Bytes - The mix digest (256 bits)-submitWork :: BytesN 8 -> BytesN 32 -> BytesN 32 -> Web3 Bool-{-# INLINE submitWork #-}-submitWork = remote "eth_submitWork"---- | Used for submitting mining hashrate.--- Parameters:--- 1. Hashrate, a hexadecimal string representation (32 bytes) of the hash rate--- 2. ID, String - A random hexadecimal(32 bytes) ID identifying the client-submitHashrate :: BytesN 32 -> BytesN 32 -> Web3 Bool-{-# INLINE submitHashrate #-}-submitHashrate = remote "eth_submitHashrate"
− src/Network/Ethereum/Web3/Net.hs
@@ -1,35 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}---- |--- Module : Network.Ethereum.Web3.Net--- Copyright : Alexander Krupenkin 2016--- License : BSD3------ Maintainer : mail@akru.me--- Stability : experimental--- Portability : unknown------ Ethereum node JSON-RPC API methods with `net_` prefix.-----module Network.Ethereum.Web3.Net where--import Data.Text (Text)-import Network.Ethereum.Web3.Provider (Web3)-import Network.Ethereum.Web3.Types (Quantity)-import Network.JsonRpc.TinyClient (remote)---- | Returns the current network id.-version :: Web3 Text-{-# INLINE version #-}-version = remote "net_version"---- | Returns true if client is actively listening for network connections.-listening :: Web3 Bool-{-# INLINE listening #-}-listening = remote "net_listening"---- | Returns number of peers currently connected to the client.-peerCount :: Web3 Quantity-{-# INLINE peerCount #-}-peerCount = remote "net_peerCount"
− src/Network/Ethereum/Web3/Provider.hs
@@ -1,94 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE MultiParamTypeClasses #-}---- |--- Module : Network.Ethereum.Web3.Provider--- Copyright : Alexander Krupenkin 2016--- License : BSD3------ Maintainer : mail@akru.me--- Stability : experimental--- Portability : portable------ Web3 service provider.-----module Network.Ethereum.Web3.Provider where--import Control.Concurrent.Async (Async, async)-import Control.Exception (Exception, try)-import Control.Monad.Catch (MonadThrow)-import Control.Monad.IO.Class (MonadIO (..))-import Control.Monad.Reader (MonadReader (..))-import Control.Monad.Trans.Reader (ReaderT, mapReaderT, runReaderT)-import Data.Aeson (FromJSON)-import Data.Default (Default (..))-import GHC.Generics (Generic)-import Network.HTTP.Client (Manager, newManager)--#ifdef TLS_MANAGER-import Network.HTTP.Client.TLS (tlsManagerSettings)-#else-import Network.HTTP.Client (defaultManagerSettings)-#endif--import Network.JsonRpc.TinyClient (Remote, ServerUri)---- | Any communication with Ethereum node wrapped with 'Web3' monad-newtype Web3 a = Web3 { unWeb3 :: ReaderT (ServerUri, Manager) IO a }- deriving (Functor, Applicative, Monad, MonadIO, MonadThrow)--instance MonadReader (ServerUri, Manager) Web3 where- ask = Web3 ask- local f = Web3 . local f . unWeb3--instance FromJSON a => Remote Web3 (Web3 a)---- | Some peace of error response-data Web3Error- = JsonRpcFail !String- -- ^ JSON-RPC communication error- | ParserFail !String- -- ^ Error in parser state- | UserFail !String- -- ^ Common head for user errors- deriving (Show, Eq, Generic)--instance Exception Web3Error----TODO: Change to `HttpProvider ServerUri | IpcProvider FilePath` to support IPC--- | Web3 Provider-data Provider = HttpProvider ServerUri- deriving (Show, Eq, Generic)--instance Default Provider where- def = HttpProvider "http://localhost:8545"---- | 'Web3' monad runner, using the supplied Manager-runWeb3With :: MonadIO m => Manager -> Provider -> Web3 a -> m (Either Web3Error a)-runWeb3With manager (HttpProvider uri) f =- liftIO . try . flip runReaderT (uri, manager) . unWeb3 $ f---- | 'Web3' monad runner-runWeb3' :: MonadIO m => Provider -> Web3 a -> m (Either Web3Error a)-runWeb3' provider f = do- manager <- liftIO $-#ifdef TLS_MANAGER- newManager tlsManagerSettings-#else- newManager defaultManagerSettings-#endif- runWeb3With manager provider f---- | 'Web3' runner for default provider-runWeb3 :: MonadIO m => Web3 a -> m (Either Web3Error a)-{-# INLINE runWeb3 #-}-runWeb3 = runWeb3' def---- | Fork 'Web3' with the same 'Provider'-forkWeb3 :: Web3 a -> Web3 (Async a)-{-# INLINE forkWeb3 #-}-forkWeb3 = Web3 . mapReaderT async . unWeb3
− src/Network/Ethereum/Web3/Types.hs
@@ -1,315 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell #-}---- |--- Module : Network.Ethereum.Web3.Types--- Copyright : Alexander Krupenkin 2016--- License : BSD3------ Maintainer : mail@akru.me--- Stability : experimental--- Portability : portable------ Ethereum generic JSON-RPC types.-----module Network.Ethereum.Web3.Types where--import Data.Aeson (FromJSON (..), Options (fieldLabelModifier, omitNothingFields),- ToJSON (..),- Value (Bool, String),- defaultOptions, object,- (.=))-import Data.Aeson.TH (deriveJSON)-import Data.Default (Default (..))-import Data.Monoid ((<>))-import Data.Ord (Down (..))-import Data.String (IsString (..))-import qualified Data.Text as T (pack)-import qualified Data.Text.Lazy.Builder as B (toLazyText)-import qualified Data.Text.Lazy.Builder.Int as B (hexadecimal)-import qualified Data.Text.Read as R (decimal, hexadecimal)-import GHC.Generics (Generic)--import Data.String.Extra (toLowerFirst)-import Network.Ethereum.ABI.Prim.Address (Address)-import Network.Ethereum.ABI.Prim.Bytes (Bytes, BytesN)-import Network.Ethereum.Unit---- | 32 byte type synonym for transaction and block hashes.-type Hash = BytesN 32---- | Should be viewed as type to representing QUANTITY in Web3 JSON RPC docs------ When encoding QUANTITIES (integers, numbers): encode as hex, prefix with "0x",--- the most compact representation (slight exception: zero should be represented as "0x0").--- Examples:------ 0x41 (65 in decimal)--- 0x400 (1024 in decimal)--- WRONG: 0x (should always have at least one digit - zero is "0x0")--- WRONG: 0x0400 (no leading zeroes allowed)--- WRONG: ff (must be prefixed 0x)-newtype Quantity = Quantity { unQuantity :: Integer }- deriving (Read, Num, Real, Enum, Eq, Ord, Generic)--instance Show Quantity where- show = show . unQuantity--instance IsString Quantity where- fromString ('0' : 'x' : hex) =- case R.hexadecimal (T.pack hex) of- Right (x, "") -> Quantity x- _ -> error "Unable to parse Quantity!"- fromString str =- case R.decimal (T.pack str) of- Right (x, "") -> Quantity x- _ -> error "Unable to parse Quantity!"--instance ToJSON Quantity where- toJSON (Quantity x) =- let hexValue = B.toLazyText (B.hexadecimal x)- in toJSON ("0x" <> hexValue)--instance FromJSON Quantity where- parseJSON (String v) =- case R.hexadecimal v of- Right (x, "") -> return (Quantity x)- _ -> fail "Unable to parse Quantity"- parseJSON _ = fail "Quantity may only be parsed from a JSON String"--instance Fractional Quantity where- (/) a b = Quantity $ div (unQuantity a) (unQuantity b)- fromRational = Quantity . floor--instance Unit Quantity where- fromWei = Quantity- toWei = unQuantity--instance UnitSpec Quantity where- divider = const 1- name = const "quantity"---- | An object with sync status data.-data SyncActive = SyncActive- { syncStartingBlock :: !Quantity- -- ^ QUANTITY - The block at which the import started (will only be reset, after the sync reached his head).- , syncCurrentBlock :: !Quantity- -- ^ QUANTITY - The current block, same as eth_blockNumber.- , syncHighestBlock :: !Quantity- -- ^ QUANTITY - The estimated highest block.- } deriving (Eq, Generic, Show)--$(deriveJSON (defaultOptions- { fieldLabelModifier = toLowerFirst . drop 4 }) ''SyncActive)---- | Sync state pulled by low-level call 'eth_syncing'.-data SyncingState = Syncing SyncActive | NotSyncing- deriving (Eq, Generic, Show)--instance FromJSON SyncingState where- parseJSON (Bool _) = pure NotSyncing- parseJSON v = Syncing <$> parseJSON v---- | Changes pulled by low-level call 'eth_getFilterChanges', 'eth_getLogs',--- and 'eth_getFilterLogs'-data Change = Change- { changeLogIndex :: !(Maybe Quantity)- -- ^ QUANTITY - integer of the log index position in the block. null when its pending log.- , changeTransactionIndex :: !(Maybe Quantity)- -- ^ QUANTITY - integer of the transactions index position log was created from. null when its pending log.- , changeTransactionHash :: !(Maybe Hash)- -- ^ DATA, 32 Bytes - hash of the transactions this log was created from. null when its pending log.- , changeBlockHash :: !(Maybe Hash)- -- ^ DATA, 32 Bytes - hash of the block where this log was in. null when its pending. null when its pending log.- , changeBlockNumber :: !(Maybe Quantity)- -- ^ QUANTITY - the block number where this log was in. null when its pending. null when its pending log.- , changeAddress :: !Address- -- ^ DATA, 20 Bytes - address from which this log originated.- , changeData :: !Bytes- -- ^ DATA - contains one or more 32 Bytes non-indexed arguments of the log.- , changeTopics :: ![BytesN 32]- -- ^ Array of DATA - Array of 0 to 4 32 Bytes DATA of indexed log arguments.- -- (In solidity: The first topic is the hash of the signature of the event- -- (e.g. Deposit(address, bytes32, uint256)), except you declared the event with- -- the anonymous specifier.)- } deriving (Eq, Show, Generic)--$(deriveJSON (defaultOptions- { fieldLabelModifier = toLowerFirst . drop 6 }) ''Change)---- | The contract call params.-data Call = Call- { callFrom :: !(Maybe Address)- -- ^ DATA, 20 Bytes - The address the transaction is send from.- , callTo :: !(Maybe Address)- -- ^ DATA, 20 Bytes - (optional when creating new contract) The address the transaction is directed to.- , callGas :: !(Maybe Quantity)- -- ^ QUANTITY - (optional, default: 3000000) Integer of the gas provided for the transaction execution. It will return unused gas.- , callGasPrice :: !(Maybe Quantity)- -- ^ QUANTITY - (optional, default: To-Be-Determined) Integer of the gasPrice used for each paid gas.- , callValue :: !(Maybe Quantity)- -- ^ QUANTITY - (optional) Integer of the value sent with this transaction.- , callData :: !(Maybe Bytes)- -- ^ DATA - The compiled code of a contract OR the hash of the invoked method signature and encoded parameters.- , callNonce :: !(Maybe Quantity)- -- ^ QUANTITY - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce.- } deriving (Eq, Show, Generic)--$(deriveJSON (defaultOptions- { fieldLabelModifier = toLowerFirst . drop 4- , omitNothingFields = True }) ''Call)--instance Default Call where- def = Call Nothing Nothing (Just 3000000) Nothing (Just 0) Nothing Nothing---- | The state of blockchain for contract call.-data DefaultBlock = BlockWithNumber Quantity- | Earliest- | Latest- | Pending- deriving (Eq, Show, Generic)--instance ToJSON DefaultBlock where- toJSON (BlockWithNumber bn) = toJSON bn- toJSON parameter = toJSON . toLowerFirst . show $ parameter---- | Low-level event filter data structure.-data Filter e = Filter- { filterAddress :: !(Maybe [Address])- -- ^ DATA|Array, 20 Bytes - (optional) Contract address or a list of addresses from which logs should originate.- , filterFromBlock :: !DefaultBlock- -- ^ QUANTITY|TAG - (optional, default: "latest") Integer block number, or "latest" for the last mined block or "pending", "earliest" for not yet mined transactions.- , filterToBlock :: !DefaultBlock- -- ^ QUANTITY|TAG - (optional, default: "latest") Integer block number, or "latest" for the last mined block or "pending", "earliest" for not yet mined transactions.- , filterTopics :: !(Maybe [Maybe (BytesN 32)])- -- ^ Array of DATA, - (optional) Array of 32 Bytes DATA topics. Topics are order-dependent. Each topic can also be an array of DATA with "or" options.- -- Topics are order-dependent. A transaction with a log with topics [A, B] will be matched by the following topic filters:- -- * [] "anything"- -- * [A] "A in first position (and anything after)"- -- * [null, B] "anything in first position AND B in second position (and anything after)"- -- * [A, B] "A in first position AND B in second position (and anything after)"- -- * [[A, B], [A, B]] "(A OR B) in first position AND (A OR B) in second position (and anything after)"- } deriving (Eq, Show, Generic)--instance ToJSON (Filter e) where- toJSON f = object [ "address" .= filterAddress f- , "fromBlock" .= filterFromBlock f- , "toBlock" .= filterToBlock f- , "topics" .= filterTopics f ]--instance Ord DefaultBlock where- compare Pending Pending = EQ- compare Latest Latest = EQ- compare Earliest Earliest = EQ- compare (BlockWithNumber a) (BlockWithNumber b) = compare a b- compare _ Pending = LT- compare Pending Latest = GT- compare _ Latest = LT- compare Earliest _ = LT- compare a b = compare (Down b) (Down a)---- | The Receipt of a Transaction-data TxReceipt = TxReceipt- { receiptTransactionHash :: !Hash- -- ^ DATA, 32 Bytes - hash of the transaction.- , receiptTransactionIndex :: !Quantity- -- ^ QUANTITY - index of the transaction.- , receiptBlockHash :: !(Maybe Hash)- -- ^ DATA, 32 Bytes - hash of the block where this transaction was in. null when its pending.- , receiptBlockNumber :: !(Maybe Quantity)- -- ^ QUANTITY - block number where this transaction was in. null when its pending.- , receiptCumulativeGasUsed :: !Quantity- -- ^ QUANTITY - The total amount of gas used when this transaction was executed in the block.- , receiptGasUsed :: !Quantity- -- ^ QUANTITY - The amount of gas used by this specific transaction alone.- , receiptContractAddress :: !(Maybe Address)- -- ^ DATA, 20 Bytes - The contract address created, if the transaction was a contract creation, otherwise null.- , receiptLogs :: ![Change]- -- ^ Array - Array of log objects, which this transaction generated.- , receiptLogsBloom :: !Bytes- -- ^ DATA, 256 Bytes - Bloom filter for light clients to quickly retrieve related logs.- , receiptStatus :: !(Maybe Quantity)- -- ^ QUANTITY either 1 (success) or 0 (failure)- } deriving (Show, Generic)--$(deriveJSON (defaultOptions- { fieldLabelModifier = toLowerFirst . drop 7 }) ''TxReceipt)---- | Transaction information.-data Transaction = Transaction- { txHash :: !Hash- -- ^ DATA, 32 Bytes - hash of the transaction.- , txNonce :: !Quantity- -- ^ QUANTITY - the number of transactions made by the sender prior to this one.- , txBlockHash :: !(Maybe Hash)- -- ^ DATA, 32 Bytes - hash of the block where this transaction was in. null when its pending.- , txBlockNumber :: !(Maybe Quantity)- -- ^ QUANTITY - block number where this transaction was in. null when its pending.- , txTransactionIndex :: !(Maybe Quantity)- -- ^ QUANTITY - integer of the transactions index position in the block. null when its pending.- , txFrom :: !Address- -- ^ DATA, 20 Bytes - address of the sender.- , txTo :: !(Maybe Address)- -- ^ DATA, 20 Bytes - address of the receiver. null when its a contract creation transaction.- , txValue :: !Quantity- -- ^ QUANTITY - value transferred in Wei.- , txGasPrice :: !Quantity- -- ^ QUANTITY - gas price provided by the sender in Wei.- , txGas :: !Quantity- -- ^ QUANTITY - gas provided by the sender.- , txInput :: !Bytes- -- ^ DATA - the data send along with the transaction.- } deriving (Eq, Show, Generic)--$(deriveJSON (defaultOptions- { fieldLabelModifier = toLowerFirst . drop 2 }) ''Transaction)---- | Block information.-data Block = Block- { blockNumber :: !(Maybe Quantity)- -- ^ QUANTITY - the block number. null when its pending block.- , blockHash :: !(Maybe Hash)- -- ^ DATA, 32 Bytes - hash of the block. null when its pending block.- , blockParentHash :: !Hash- -- ^ DATA, 32 Bytes - hash of the parent block.- , blockNonce :: !(Maybe Bytes)- -- ^ DATA, 8 Bytes - hash of the generated proof-of-work. null when its pending block.- , blockSha3Uncles :: !(BytesN 32)- -- ^ DATA, 32 Bytes - SHA3 of the uncles data in the block.- , blockLogsBloom :: !(Maybe Bytes)- -- ^ DATA, 256 Bytes - the bloom filter for the logs of the block. null when its pending block.- , blockTransactionsRoot :: !(BytesN 32)- -- ^ DATA, 32 Bytes - the root of the transaction trie of the block.- , blockStateRoot :: !(BytesN 32)- -- ^ DATA, 32 Bytes - the root of the final state trie of the block.- , blockReceiptRoot :: !(Maybe (BytesN 32))- -- ^ DATA, 32 Bytes - the root of the receipts trie of the block.- , blockMiner :: !Address- -- ^ DATA, 20 Bytes - the address of the beneficiary to whom the mining rewards were given.- , blockDifficulty :: !Quantity- -- ^ QUANTITY - integer of the difficulty for this block.- , blockTotalDifficulty :: !Quantity- -- ^ QUANTITY - integer of the total difficulty of the chain until this block.- , blockExtraData :: !Bytes- -- ^ DATA - the "extra data" field of this block.- , blockSize :: !Quantity- -- ^ QUANTITY - integer the size of this block in bytes.- , blockGasLimit :: !Quantity- -- ^ QUANTITY - the maximum gas allowed in this block.- , blockGasUsed :: !Quantity- -- ^ QUANTITY - the total used gas by all transactions in this block.- , blockTimestamp :: !Quantity- -- ^ QUANTITY - the unix timestamp for when the block was collated.- , blockTransactions :: ![Transaction]- -- ^ Array of transaction objects.- , blockUncles :: ![Hash]- -- ^ Array - Array of uncle hashes.- } deriving (Show, Generic)--$(deriveJSON (defaultOptions- { fieldLabelModifier = toLowerFirst . drop 5 }) ''Block)
− src/Network/Ethereum/Web3/Web3.hs
@@ -1,31 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}---- |--- Module : Network.Ethereum.Web3.Web3--- Copyright : Alexander Krupenkin 2016--- License : BSD3------ Maintainer : mail@akru.me--- Stability : experimental--- Portability : unknown------ Ethereum node JSON-RPC API methods with `web3_` prefix.-----module Network.Ethereum.Web3.Web3 where--import Data.Text (Text)-import Network.Ethereum.ABI.Prim.Bytes (Bytes)-import Network.Ethereum.Web3.Provider (Web3)-import Network.Ethereum.Web3.Types (Hash)-import Network.JsonRpc.TinyClient (remote)---- | Returns current node version string.-clientVersion :: Web3 Text-{-# INLINE clientVersion #-}-clientVersion = remote "web3_clientVersion"---- | Returns Keccak-256 (not the standardized SHA3-256) of the given data.-sha3 :: Bytes -> Web3 Hash-{-# INLINE sha3 #-}-sha3 = remote "web3_sha3"
src/Network/JsonRpc/TinyClient.hs view
@@ -1,9 +1,12 @@-{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} @@ -20,54 +23,107 @@ -- Functions for implementing the client side of JSON-RPC 2.0. -- See <http://www.jsonrpc.org/specification>. --+-- If you have monad with 'MonadIO', 'MonadThrow' and 'MonadReader' instances,+-- it can be used as base for JSON-RPC calls.+--+-- Example:+--+-- @+-- newtype MyMonad a = ...+--+-- instance JsonRpc MyMonad+--+-- foo :: Mymonad Text+-- foo = remote "foo"+-- @+--+-- Arguments of function are stored into @params@ request array.+--+-- Example:+--+-- @+-- myMethod :: JsonRpc m => Int -> Bool -> m String+-- myMethod = remote "myMethod"+-- @+-- -module Network.JsonRpc.TinyClient (- JsonRpcException(..)- , RpcError(..)- , MethodName- , ServerUri- , Remote- , remote- ) where+module Network.JsonRpc.TinyClient+ (+ -- * The JSON-RPC remote call monad+ JsonRpc(..)+ , MethodName -import Control.Applicative ((<|>))-import Control.Exception (Exception)-import Control.Monad ((<=<))-import Control.Monad.Catch (MonadThrow, throwM)-import Control.Monad.IO.Class (MonadIO, liftIO)-import Control.Monad.Reader (MonadReader, ask)-import Data.Aeson-import Data.ByteString.Lazy (ByteString)-import Data.Text (Text, unpack)-import Network.HTTP.Client (Manager, RequestBody (RequestBodyLBS),- httpLbs, method, parseRequest,- requestBody, requestHeaders,- responseBody)+ -- * JSON-RPC client settings+ , JsonRpcClient+ , defaultSettings+ , jsonRpcServer+ , jsonRpcManager --- | Name of called method.-type MethodName = Text+ -- * Error handling+ , JsonRpcException(..)+ , RpcError(..)+ ) where --- | JSON-RPC server URI-type ServerUri = String+import Control.Applicative ((<|>))+import Control.Exception (Exception)+import Control.Monad ((<=<))+import Control.Monad.Catch (MonadThrow (..))+import Control.Monad.IO.Class (MonadIO (..))+import Control.Monad.State (MonadState)+import Crypto.Number.Generate (generateMax)+import Data.Aeson (FromJSON (..), ToJSON (..),+ Value (String), eitherDecode, encode,+ object, withObject, (.:), (.:?), (.=))+import Data.ByteString.Lazy (ByteString)+import Data.Text (Text, unpack)+import Lens.Micro.Mtl (use)+import Lens.Micro.TH (makeLenses)+import Network.HTTP.Client (Manager, RequestBody (RequestBodyLBS),+ httpLbs, method, newManager,+ parseRequest, requestBody,+ requestHeaders, responseBody)+import Network.HTTP.Client.TLS (tlsManagerSettings) --- | JSON-RPC minimal client config-type Config = (ServerUri, Manager)+-- | JSON-RPC monad constrait.+type JsonRpcM m = (MonadIO m, MonadThrow m, MonadState JsonRpcClient m) +-- | JSON-RPC client state vars.+data JsonRpcClient = JsonRpcClient+ { _jsonRpcManager :: Manager -- ^ HTTP connection manager.+ , _jsonRpcServer :: String -- ^ Remote server URI.+ }++$(makeLenses ''JsonRpcClient)++-- | Create default 'JsonRpcClient' settings.+defaultSettings :: MonadIO m+ => String -- ^ JSON-RPC server URI+ -> m JsonRpcClient+defaultSettings srv = liftIO $ JsonRpcClient+ <$> newManager tlsManagerSettings+ <*> pure srv++instance Show JsonRpcClient where+ show JsonRpcClient{..} = "JsonRpcClient<" ++ _jsonRpcServer ++ ">"+ -- | JSON-RPC request.-data Request = Request { rqMethod :: !Text- , rqId :: !Int- , rqParams :: !Value }+data Request = Request+ { rqMethod :: !Text+ , rqId :: !Int+ , rqParams :: !Value+ } deriving (Eq, Show) instance ToJSON Request where toJSON rq = object [ "jsonrpc" .= String "2.0" , "method" .= rqMethod rq , "params" .= rqParams rq- , "id" .= rqId rq ]+ , "id" .= rqId rq+ ] -- | JSON-RPC response. data Response = Response- { rsResult :: !(Either RpcError Value)- } deriving (Eq, Show)+ { rsResult :: !(Either RpcError Value)+ } deriving (Eq, Show) instance FromJSON Response where parseJSON =@@ -77,10 +133,10 @@ -- | JSON-RPC error message data RpcError = RpcError- { errCode :: !Int- , errMessage :: !Text- , errData :: !(Maybe Value)- } deriving Eq+ { errCode :: !Int+ , errMessage :: !Text+ , errData :: !(Maybe Value)+ } deriving Eq instance Show RpcError where show (RpcError code msg dat) =@@ -93,69 +149,51 @@ <*> v .: "message" <*> v .:? "data" --- | Typeclass for JSON-RPC monad base.------ If you have monad with 'MonadIO', 'MonadThrow' and 'MonadReader' instances,--- it can be used as base for JSON-RPC calls.------ Example:------ @--- newtype MyMonad a = ...------ instance Remote MyMonad (Mymonad a)------ foo :: Int -> Bool -> Mymonad Text--- foo = remote "foo"--- @----class (MonadIO m, MonadThrow m, MonadReader Config m) => Remote m a | a -> m where- remote_ :: ([Value] -> m ByteString) -> a+data JsonRpcException+ = ParsingException String+ | CallException RpcError+ deriving (Show, Eq) - default remote_ :: (FromJSON b, m b ~ a) => ([Value] -> m ByteString) -> a- remote_ f = decodeResponse =<< f []+instance Exception JsonRpcException +class JsonRpcM m => Remote m a | a -> m where+ remote' :: ([Value] -> m ByteString) -> a+ instance (ToJSON a, Remote m b) => Remote m (a -> b) where- remote_ f x = remote_ (\xs -> f (toJSON x : xs))+ remote' f x = remote' (\xs -> f (toJSON x : xs)) --- | Remote call of JSON-RPC method.------ Arguments of function are stored into @params@ request array.------ Example:------ @--- myMethod :: Int -> Bool -> m String--- myMethod = remote "myMethod"--- @----remote :: Remote m a => MethodName -> a-{-# INLINE remote #-}-remote = remote_ . call+instance {-# INCOHERENT #-} (JsonRpcM m, FromJSON b) => Remote m (m b) where+ remote' f = decodeResponse =<< f [] -call :: (MonadIO m,- MonadThrow m,- MonadReader Config m)+-- | Name of called method.+type MethodName = Text++-- | JSON-RPC call monad.+class JsonRpcM m => JsonRpc m where+ -- | Remote call of JSON-RPC method.+ remote :: Remote m a => MethodName -> a+ {-# INLINE remote #-}+ remote = remote' . call++call :: JsonRpcM m => MethodName -> [Value] -> m ByteString-call n = connection . encode . Request n 1 . toJSON+call m r = do+ rid <- liftIO $ generateMax maxInt+ connection . encode $ Request m (fromInteger rid) (toJSON r) where+ maxInt = toInteger (maxBound :: Int) connection body = do- (uri, manager) <- ask- request <- parseRequest uri+ serverUri <- use jsonRpcServer+ request <- parseRequest serverUri let request' = request { requestBody = RequestBodyLBS body , requestHeaders = [("Content-Type", "application/json")]- , method = "POST" }+ , method = "POST"+ }+ manager <- use jsonRpcManager responseBody <$> liftIO (httpLbs request' manager)--data JsonRpcException- = ParsingException String- | CallException RpcError- deriving (Eq, Show)--instance Exception JsonRpcException decodeResponse :: (MonadThrow m, FromJSON a) => ByteString
+ stack.yaml view
@@ -0,0 +1,27 @@+# Resolver to choose a 'specific' stackage snapshot or a compiler version.+resolver: lts-12.14++# User packages to be built.+packages:+- '.'++# Extra package dependencies+extra-deps:+- secp256k1-haskell-0.1.4+- relapse-1.0.0.0+- vinyl-0.9.3++# Dependencies bounds+pvp-bounds: both++# Nix integration+nix:+ packages:+ - zlib+ - boost+ - jsoncpp+ - solc+ - solc.dev+ - secp256k1+ - haskellPackages.hlint+ - haskellPackages.stylish-haskell
− test-support/contracts/Migrations.sol
@@ -1,23 +0,0 @@-pragma solidity ^0.4.4;--contract Migrations {- address public owner;- uint public last_completed_migration;-- modifier restricted() {- if (msg.sender == owner) _;- }-- function Migrations() {- owner = msg.sender;- }-- function setCompleted(uint completed) restricted {- last_completed_migration = completed;- }-- function upgrade(address new_address) restricted {- Migrations upgraded = Migrations(new_address);- upgraded.setCompleted(last_completed_migration);- }-}
− test-support/contracts/SimpleStorage.sol
@@ -1,12 +0,0 @@-pragma solidity ^0.4.15;--contract SimpleStorage {- uint public count;- - event CountSet(uint _count);- - function setCount(uint _count) {- count = _count;- CountSet(_count);- }-}
− test-support/convertAbi.sh
@@ -1,9 +0,0 @@-#!/bin/sh-set -xe-cd build/contracts/-mkdir -p abis--for file in *.json; do- jq '.abi' < "$file" > "abis/$file"-done-
− test-support/inject-contract-addresses.sh
@@ -1,26 +0,0 @@-#!/usr/bin/env bash--set -ex--EXPORT_STORE=${EXPORT_STORE:-/tmp/detected-vars}-SEARCH_DIRECTORY=${SEARCH_DIRECTORY:-build/contracts}--function detect_contract_addresses() {- for file in $(find $SEARCH_DIRECTORY -maxdepth 1 -type f -name '*.json'); do- maybe_address=`jq -r .networks[].address $file | grep -v null | head -n 1`- if [ -z "${maybe_address}" ]; then- echo no addresses detected for $file >&2- else- contract_name=`echo $file | sed -e 's@'$SEARCH_DIRECTORY'/@@g' -e 's/.json//g'`- echo found address "${maybe_address}" for "${contract_name}" >&2- contract_var=`echo $contract_name | tr '[:lower:]' '[:upper:]'`_CONTRACT_ADDRESS- echo the var for "${contract_name}" is "${contract_var}" >&2- echo "export ${contract_var}=`echo ${maybe_address} | sed s/0x//`"- fi- done-}--detect_contract_addresses 2>/dev/null >$EXPORT_STORE--source $EXPORT_STORE-$@
− test-support/migrations/1_initial_migration.js
@@ -1,5 +0,0 @@-var Migrations = artifacts.require("./Migrations.sol");--module.exports = function(deployer) {- deployer.deploy(Migrations);-};
− test-support/migrations/2_deploy_contracts.js
@@ -1,7 +0,0 @@-var SimpleStorage = artifacts.require("./SimpleStorage.sol");-var ComplexStorage = artifacts.require("./ComplexStorage.sol");--module.exports = function(deployer) {- deployer.deploy(SimpleStorage);- deployer.deploy(ComplexStorage);-};
− test-support/truffle.js
@@ -1,9 +0,0 @@-module.exports = {- networks: {- development: {- host: "localhost",- port: 8545,- network_id: "*" // Match any network id- }- }-};
test/Network/Ethereum/Web3/Test/ComplexStorageSpec.hs view
@@ -1,7 +1,9 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedLists #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-}@@ -25,29 +27,30 @@ module Network.Ethereum.Web3.Test.ComplexStorageSpec where import Control.Concurrent.Async (wait)-import Control.Concurrent.MVar+import Control.Concurrent.MVar (newEmptyMVar, putMVar,+ takeMVar) import Control.Monad.IO.Class (liftIO)-import Data.ByteArray (convert)-import Data.ByteString (ByteString)-import Data.Default-import Data.Either (isRight)-import Data.Maybe-import Data.String (fromString)+import Data.Default (def)++import Network.Ethereum.Api.Types (Filter (..))+import Network.Ethereum.Contract (new) import Network.Ethereum.Contract.TH import Network.Ethereum.Web3 hiding (convert)-import qualified Network.Ethereum.Web3.Eth as Eth import Network.Ethereum.Web3.Test.Utils-import Network.Ethereum.Web3.Types (Call (..), Filter (..))-import System.Environment (getEnv)-import System.IO.Unsafe (unsafePerformIO)++ import Test.Hspec -[abiFrom|test-support/build/contracts/abis/ComplexStorage.json|]+[abiFrom|test/contracts/ComplexStorage.json|] +deploy :: IO Address+deploy = do+ Just address <- web3 $ withAccount () $ withParam id $ new ComplexStorageContract+ putStrLn $ "ComplexStorage: " ++ show address+ return address+ spec :: Spec-spec = describe "Complex Storage" $ do- it "should inject contract addresses" injectExportedEnvironmentVariables- withPrimaryEthereumAccount `before` complexStorageSpec+spec = deploy `before` complexStorageSpec complexStorageSpec :: SpecWith Address complexStorageSpec = do@@ -65,27 +68,25 @@ sByte2sVec = [sByte2sElem, sByte2sElem, sByte2sElem, sByte2sElem] sByte2s = [sByte2sVec, sByte2sVec] - it "can set the values of a ComplexStorage and validate them with an event" $ \primaryAccount -> do- contractAddress <- Prelude.fmap fromString . liftIO $ getEnv "COMPLEXSTORAGE_CONTRACT_ADDRESS"- let theCall = callFromTo primaryAccount contractAddress- fltr = (def :: Filter ValsSet) { filterAddress = Just [contractAddress] }+ it "can set the values of a ComplexStorage and validate them with an event" $ \storage -> do+ let fltr = (def :: Filter ValsSet) { filterAddress = Just [storage] } -- kick off listening for the ValsSet event vals <- newEmptyMVar- fiber <- runWeb3Configured' $+ fiber <- web3 $ event fltr $ \vs -> do liftIO $ putMVar vals vs pure TerminateEvent -- kick off tx- ret <- runWeb3Configured $ setValues theCall- sUint- sInt- sBool- sInt224- sBools- sInts- sString- sBytes16- sByte2s+ _ <- contract storage $ setValues+ sUint+ sInt+ sBool+ sInt224+ sBools+ sInts+ sString+ sBytes16+ sByte2s -- wait for its ValsSet event wait fiber (ValsSet vsA vsB vsC vsD vsE vsF vsG vsH vsI) <- takeMVar vals@@ -99,33 +100,53 @@ vsH `shouldBe` sBytes16 vsI `shouldBe` sByte2s - it "can verify that it set the values correctly" $ \primaryAccount -> do- contractAddress <- Prelude.fmap fromString . liftIO $ getEnv "COMPLEXSTORAGE_CONTRACT_ADDRESS"- let theCall = callFromTo primaryAccount contractAddress- runGetterCall f = runWeb3Configured (f theCall)- -- there really has to be a better way to do this- uintVal' <- runGetterCall uintVal- intVal' <- runGetterCall intVal- boolVal' <- runGetterCall boolVal- int224Val' <- runGetterCall int224Val- boolsVal <- runGetterCall $ \c -> boolVectorVal c 0- intsVal <- runGetterCall $ \c -> intListVal c 0- stringVal' <- runGetterCall stringVal- bytes16Val' <- runGetterCall bytes16Val- bytes2s <- runGetterCall $ \c -> bytes2VectorListVal c 0 0+ it "can verify that it set the values correctly" $ \storage -> do+ -- Write a values+ _ <- contract storage $ setValues+ sUint+ sInt+ sBool+ sInt224+ sBools+ sInts+ sString+ sBytes16+ sByte2s+ -- Read a couple of values+ (uintVal', intVal', boolVal', int224Val', boolsVal, intsVal, stringVal', bytes16Val', bytes2s)+ <- contract storage $ (,,,,,,,,)+ <$> uintVal+ <*> intVal+ <*> boolVal+ <*> int224Val+ <*> boolVectorVal 0+ <*> intListVal 0+ <*> stringVal+ <*> bytes16Val+ <*> bytes2VectorListVal 0 0+ uintVal' `shouldBe` sUint intVal' `shouldBe` sInt boolVal' `shouldBe` sBool int224Val' `shouldBe` sInt224 boolsVal `shouldBe` True- intsVal `shouldBe` sInts Prelude.!! 0+ intsVal `shouldBe` head sInts stringVal' `shouldBe` sString bytes16Val' `shouldBe` sBytes16- bytes2s `shouldBe` sByte2sElem+ bytes2s `shouldBe` sByte2sElem - it "can decode a complicated value correctly" $ \primaryAccount -> do- contractAddress <- Prelude.fmap fromString . liftIO $ getEnv "COMPLEXSTORAGE_CONTRACT_ADDRESS"- let theCall = callFromTo primaryAccount contractAddress- runGetterCall f = runWeb3Configured (f theCall)- allVals <- runGetterCall getVals+ it "can decode a complicated value correctly" $ \storage -> do+ -- Write a values+ _ <- contract storage $ setValues+ sUint+ sInt+ sBool+ sInt224+ sBools+ sInts+ sString+ sBytes16+ sByte2s+ -- Read a all values+ allVals <- contract storage getVals allVals `shouldBe` (sUint, sInt, sBool, sInt224, sBools, sInts, sString, sBytes16, sByte2s)
+ test/Network/Ethereum/Web3/Test/ERC20Spec.hs view
@@ -0,0 +1,24 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+module Network.Ethereum.Web3.Test.ERC20Spec where++import Test.Hspec++import Network.Ethereum.Contract.TH (abiFrom)+import Network.Ethereum.Web3 (Account, UIntN)+import Network.JsonRpc.TinyClient (JsonRpc)++[abiFrom|examples/token/ERC20.json|]++-- this spec is just to test compilation+spec :: Spec+spec = return ()++getBalance :: (JsonRpc m, Account p t, Functor (t m))+ => t m (UIntN 256)+getBalance = balanceOf "0x1234567890123456789011234567890234567890"
+ test/Network/Ethereum/Web3/Test/LinearizationSpec.hs view
@@ -0,0 +1,192 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeApplications #-}++-- Module : Network.Ethereum.Web3.Test.SimpleStorage+-- Copyright : Alexander Krupenkin 2016+-- License : BSD3+--+-- Maintainer : mail@akru.me+-- Stability : experimental+-- Portability : unportable+--+-- SimpleStorage is a Solidity contract which stores a uint256.+-- The point of this test is to test function calls to update and+-- read the value, as well as an event monitor.++module Network.Ethereum.Web3.Test.LinearizationSpec where++import Control.Concurrent (forkIO)+import Control.Concurrent.Async (forConcurrently_)+import Control.Concurrent.MVar+import Control.Concurrent.STM (atomically)+import Control.Concurrent.STM.TQueue (TQueue, flushTQueue,+ newTQueueIO, writeTQueue)+import Control.Monad (void)+import Control.Monad.IO.Class (MonadIO (..))+import Control.Monad.Trans.Reader (ReaderT, ask)+import Data.Default+import Data.Either+import Data.List (sort)+import Data.Maybe (fromJust)+import System.Random (randomRIO)+import Test.Hspec++import qualified Network.Ethereum.Api.Eth as Eth+import Network.Ethereum.Api.Types (Change (..), Filter (..),+ TxReceipt, unQuantity)+import Network.Ethereum.Contract (new)+import Network.Ethereum.Contract.Event+import Network.Ethereum.Contract.TH (abiFrom)+import Network.Ethereum.Web3+import Network.Ethereum.Web3.Test.Utils++[abiFrom|test/contracts/Linearization.json|]++deploy :: IO Address+deploy = do+ Just address <- web3 $ withAccount () $ withParam id $ new LinearizationContract+ putStrLn $ "Linearization: " ++ show address+ return address++spec :: Spec+spec = do+ deploy `before` linearizationSpec+ deploy `before` floodSpec++floodCount :: Int+floodCount = 200++linearizationSpec :: SpecWith Address+linearizationSpec =+ describe "can bundle and linearize events" $ do+ it "can call e12" $ \linearization -> do+ var <- monitorE1OrE2 linearization+ _ <- contract linearization e12+ res <- takeMVar var+ res `shouldSatisfy` isLeft++ it "can call e21" $ \linearization -> do+ -- wait on the next block+ web3 Eth.blockNumber >>= \bn -> awaitBlock (bn + 1)+ var <- monitorE1OrE2 linearization+ _ <- contract linearization e21+ res <- takeMVar var+ res `shouldSatisfy` isRight++singleFlood :: forall m. (MonadIO m) => Address -> m TxReceipt+singleFlood linearization = liftIO $ do+ rando :: Int <- randomRIO (1, 4)+ contract linearization $+ case rando of+ 1 -> e1+ 2 -> e2+ 3 -> e3+ 4 -> e4+ _ -> error "got a number outside of (1,4) after randomR (1,4)"++floodSpec :: SpecWith Address+floodSpec = describe "can correctly demonstrate the difference between `multiEvent` and multiple `event'`s" $ do+ it "properly linearizes with `multiEvent` when flooded and doesn't with multiple `event`s" $ \linearization -> do+ multiQ <- monitorAllFourMulti linearization+ parQ <- monitorAllFourPar linearization+ -- to let the filter settle so we dont block indefinitely on missing events?+ sleepBlocks 10++ -- flood em and wait for all to finish+ liftIO . forConcurrently_ [1..floodCount] . const $ singleFlood linearization++ -- to let the event listeners catch up+ sleepBlocks 10++ -- wait for all multiEvents to be received and flush em out+ multiReceivedEvents <- liftIO . atomically $ flushTQueue multiQ+ parReceivedEvents <- liftIO . atomically $ flushTQueue parQ++ -- did we get at least 1/4 of the events? (this is a gotcha when flooding, sometimes nonces get repeated)+ length multiReceivedEvents `shouldSatisfy` (>= (floodCount `div` 4))+ length parReceivedEvents `shouldSatisfy` (>= (floodCount `div` 4))++ -- did both listeners see the same amount of events?+ length multiReceivedEvents `shouldBe` length parReceivedEvents++ -- the events pushed into the multi TQueue should already be sorted if they happened in the right order+ sort multiReceivedEvents `shouldBe` multiReceivedEvents+ -- the events pushed into the TQueue should not be sorted if they didnt come in in the right order+ sort parReceivedEvents `shouldNotBe` parReceivedEvents++monitorE1OrE2 :: Address -> IO (MVar (Either E1 E2))+monitorE1OrE2 addr = do+ var <- newEmptyMVar+ let fltr1 = (def :: Filter E1) { filterAddress = Just [addr] }+ fltr2 = (def :: Filter E2) { filterAddress = Just [addr] }+ filters = fltr1 :? fltr2 :? NilFilters+ handler1 ev1 = do+ liftIO $ putMVar var (Left ev1)+ return TerminateEvent+ handler2 ev2 = do+ liftIO $ putMVar var (Right ev2)+ return TerminateEvent+ handlers = H handler1 :& H handler2 :& RNil+ _ <- web3 $ multiEvent filters handlers+ return var++data EventTag = ETE1 | ETE2 | ETE3 | ETE4+ deriving (Eq, Read, Show)++instance {-# OVERLAPPING #-} Ord (EventTag, Integer, Integer) where+ (_, b1, t1) `compare` (_, b2, t2) =+ let bCmp = b1 `compare` b2+ in if bCmp == EQ then t1 `compare` t2+ else bCmp++monitorAllFourMulti :: Address+ -> IO (TQueue (EventTag, Integer, Integer))+monitorAllFourMulti addr = do+ q <- newTQueueIO+ let f :: forall a. Default (Filter a) => Filter a+ f = defFilter addr+ h = enqueueingHandler q+ filters = f @E1 :? f @E2 :? f @E3 :? f @E4 :? NilFilters+ handlers = h ETE1 :& h ETE2 :& h ETE3 :& h ETE4 :& RNil+ void . web3 $ multiEvent filters handlers+ return q++monitorAllFourPar :: Address+ -> IO (TQueue (EventTag, Integer, Integer))+monitorAllFourPar addr = do+ q <- newTQueueIO+ let f :: forall a. Default (Filter a) => Filter a+ f = defFilter addr+ h = enqueueingHandler q+ unH (H h) = h++ void . forkIO . web3 $ event' (f @E1) (unH $ h ETE1)+ void . forkIO . web3 $ event' (f @E2) (unH $ h ETE2)+ void . forkIO . web3 $ event' (f @E3) (unH $ h ETE3)+ void . forkIO . web3 $ event' (f @E4) (unH $ h ETE4)+ return q++defFilter :: forall a. Default (Filter a) => Address -> Filter a+defFilter addr = (def :: Filter a) { filterAddress = Just [addr] }++enqueueingHandler :: forall a. TQueue (EventTag, Integer, Integer)+ -> EventTag+ -> Handler (ReaderT Change Web3 EventAction) a+enqueueingHandler q tag = H . const $ do+ Change{..} <- ask+ let bn = unQuantity $ fromJust changeBlockNumber+ li = unQuantity $ fromJust changeLogIndex+ liftIO . atomically $ writeTQueue q (tag, bn, li)+ return ContinueEvent
+ test/Network/Ethereum/Web3/Test/RegistrySpec.hs view
@@ -0,0 +1,32 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedLists #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE TemplateHaskell #-}++module Network.Ethereum.Web3.Test.RegistrySpec where++import Data.Default (def)+import Test.Hspec (Spec)++import Network.Ethereum.Api.Types (Filter)+import Network.Ethereum.Contract.TH (abiFrom)+import Network.Ethereum.Web3 (EventAction (TerminateEvent),+ Web3, event)++[abiFrom|test/contracts/Registry.json|]++-- this spec is just to test compilation+spec :: Spec+spec = return ()++monitor :: Web3 ()+monitor = do+ let fltr1 = def :: Filter A+ fltr2 = def :: Filter B+ event fltr1 $ \_ -> pure TerminateEvent+ event fltr2 $ \_ -> pure TerminateEvent+ pure ()
test/Network/Ethereum/Web3/Test/SimpleStorageSpec.hs view
@@ -1,9 +1,11 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE ScopedTypeVariables #-}@@ -20,172 +22,157 @@ -- SimpleStorage is a Solidity contract which stores a uint256. -- The point of this test is to test function calls to update and -- read the value, as well as an event monitor.+-- module Network.Ethereum.Web3.Test.SimpleStorageSpec where -import Control.Concurrent (threadDelay) import Control.Concurrent.Async (wait) import Control.Concurrent.MVar-import Control.Monad (void) import Control.Monad.IO.Class (liftIO) import Control.Monad.Trans.Class (lift) import Control.Monad.Trans.Reader (ask)-import Data.ByteString (ByteString)-import Data.Default-import Data.Either (isRight)-import Data.Foldable (forM_)+import Data.Default (def) import Data.List (sort)-import Data.Maybe-import Data.Monoid-import Data.String (fromString)-import qualified Data.Text as T-import Data.Traversable (for)-import GHC.TypeLits+import Data.Monoid ((<>))+import Test.Hspec +import qualified Network.Ethereum.Api.Eth as Eth+import Network.Ethereum.Api.Provider (forkWeb3)+import Network.Ethereum.Api.Types+import Network.Ethereum.Contract (new)+import Network.Ethereum.Contract.Event (event') import Network.Ethereum.Contract.TH-import Network.Ethereum.Web3 hiding (convert)-import qualified Network.Ethereum.Web3.Eth as Eth-import Network.Ethereum.Web3.Provider (forkWeb3)-import Network.Ethereum.Web3.Types+import Network.Ethereum.Web3 -import Numeric (showHex)-import System.Environment (getEnv)-import System.IO.Unsafe (unsafePerformIO)-import Test.Hspec import Network.Ethereum.Web3.Test.Utils -[abiFrom|test-support/build/contracts/abis/SimpleStorage.json|]+[abiFrom|test/contracts/SimpleStorage.json|] -unCountSet :: CountSet -> UIntN 256-unCountSet (CountSet n) = n+unEvT_CountSet :: EvT_CountSet -> UIntN 256+unEvT_CountSet (EvT_CountSet n) = n -contractAddress :: Address-contractAddress = fromString . unsafePerformIO $ getEnv "SIMPLESTORAGE_CONTRACT_ADDRESS"+deploy :: IO Address+deploy = do+ Just address <- web3 $ withAccount () $ withParam id $ new SimpleStorageContract+ putStrLn $ "SimpleStorage: " ++ show address+ return address spec :: Spec-spec = describe "Simple Storage" $ do- it "should inject contract addresses" injectExportedEnvironmentVariables- withPrimaryEthereumAccount `before` interactions- withPrimaryEthereumAccount `before` events+spec = deploy `before` do+ interactions+ events interactions :: SpecWith Address interactions = describe "can interact with a SimpleStorage contract" $ do -- todo: this should ideally be arbitrary! let theValue = 12345- it "can set the value of a SimpleStorage contract" $ \primaryAccount -> do- let theCall = callFromTo primaryAccount contractAddress- ret <- runWeb3Configured $ setCount theCall theValue- True `shouldBe` True -- we need to get this far - it "can read the value back" $ \primaryAccount -> do- let theCall = callFromTo primaryAccount contractAddress- now <- runWeb3Configured Eth.blockNumber+ it "can set the value of a SimpleStorage contract and read the value back" $ \storage -> do+ _ <- contract storage $ setCount theValue++ now <- web3 Eth.blockNumber let later = now + 3 awaitBlock later- v <- runWeb3Configured (count theCall)++ v <- contract storage count v `shouldBe` theValue events :: SpecWith Address-events = describe "can interact with a SimpleStorage contract across block intervals" $ do- it "can stream events starting and ending in the future, unbounded" $ \primaryAccount -> do- var <- newMVar []- let theCall = callFromTo primaryAccount contractAddress- theSets = [1, 2, 3]- print "Setting up the filter..."- fiber <- runWeb3Configured' $ do- let fltr = (def :: Filter CountSet) { filterAddress = Just [contractAddress] }- forkWeb3 $ processUntil' var fltr ((3 ==) . length)- print "Setting the values..."- setValues theCall theSets- wait fiber- print "Filter caught 3 values..."- vals <- takeMVar var- sort (unCountSet <$> vals) `shouldBe` sort theSets+events = do+ describe "can interact with a SimpleStorage contract across block intervals" $ do+ it "can stream events starting and ending in the future, unbounded" $ \storage -> do+ var <- newMVar []+ let theSets = [1, 2, 3]+ putStrLn "Setting up the filter..."+ fiber <- web3 $ do+ let fltr = (def :: Filter EvT_CountSet) { filterAddress = Just [storage] }+ forkWeb3 $ processUntil' var fltr ((3 ==) . length)+ putStrLn "Setting the values..."+ setValues storage theSets+ wait fiber+ putStrLn "Filter caught 3 values..."+ vals <- takeMVar var+ sort (unEvT_CountSet <$> vals) `shouldBe` sort theSets - it "can stream events starting and ending in the future, bounded" $ \primaryAccount -> do- runWeb3Configured Eth.blockNumber >>= \bn -> awaitBlock (bn + 1)- var <- newMVar []- let theCall = callFromTo primaryAccount contractAddress- theSets = [13, 14, 15]- start <- runWeb3Configured Eth.blockNumber- let later = BlockWithNumber (start + 3)- latest = BlockWithNumber (start + 8)- fltr = (def :: Filter CountSet) { filterAddress = Just [contractAddress]- , filterFromBlock = later- , filterToBlock = latest }- print "Setting up the filter..."- fiber <- runWeb3Configured' $- forkWeb3 $ processUntil' var fltr ((3 ==) . length)- awaitBlock (start + 3)- print "Setting the values..."- setValues theCall theSets- wait fiber- print "Filter caught 3 values..."- vals <- takeMVar var- sort (unCountSet <$> vals) `shouldBe` sort theSets+ it "can stream events starting and ending in the future, bounded" $ \storage -> do+ var <- newMVar []+ let theSets = [13, 14, 15]+ start <- web3 Eth.blockNumber+ let later = BlockWithNumber (start + 3)+ latest = BlockWithNumber (start + 8)+ fltr = (def :: Filter EvT_CountSet) { filterAddress = Just [storage]+ , filterFromBlock = later+ , filterToBlock = latest+ }+ putStrLn "Setting up the filter..."+ fiber <- web3 $+ forkWeb3 $ processUntil' var fltr ((3 ==) . length)+ awaitBlock (start + 3)+ putStrLn "Setting the values..."+ setValues storage theSets+ wait fiber+ putStrLn "Filter caught 3 values..."+ vals <- takeMVar var+ sort (unEvT_CountSet <$> vals) `shouldBe` init (sort theSets) - it "can stream events starting in the past and ending in the future" $ \primaryAccount -> do- runWeb3Configured Eth.blockNumber >>= \bn -> awaitBlock (bn + 1)- var <- newMVar []- blockNumberVar <- newEmptyMVar- let theCall = callFromTo primaryAccount contractAddress- theSets1 = [7, 8, 9]- theSets2 = [10, 11, 12]- start <- runWeb3Configured Eth.blockNumber- let fltr = (def :: Filter CountSet) { filterAddress = Just [contractAddress] }- fiber <- runWeb3Configured' $ do- forkWeb3 $ processUntil var fltr ((3 ==) . length) (liftIO . putMVar blockNumberVar . changeBlockNumber)- print "Running first transactions as past transactions..."- setValues theCall theSets1- wait fiber- print "All past transactions succeeded... "- Just end <- takeMVar blockNumberVar- awaitBlock $ end + 1 -- make past transactions definitively in past- var' <- newMVar []- fiber <- runWeb3Configured' $ do- let fltr = (def :: Filter CountSet) { filterAddress = Just [contractAddress]- , filterFromBlock = BlockWithNumber start}- forkWeb3 $ processUntil' var' fltr ((6 ==) . length)- print "Setting more values"- setValues theCall theSets2- wait fiber- print "All new values have ben set"- vals <- takeMVar var'- sort (unCountSet <$> vals) `shouldBe` sort (theSets1 <> theSets2)+ it "can stream events starting in the past and ending in the future" $ \storage -> do+ var <- newMVar []+ blockNumberVar <- newEmptyMVar+ let theSets1 = [7, 8, 9]+ theSets2 = [10, 11, 12]+ start <- web3 Eth.blockNumber+ let fltr = (def :: Filter EvT_CountSet) { filterAddress = Just [storage] }+ fiber <- web3 $ do+ forkWeb3 $ processUntil var fltr ((3 ==) . length) (liftIO . putMVar blockNumberVar . changeBlockNumber)+ putStrLn "Running first transactions as past transactions..."+ setValues storage theSets1+ wait fiber+ putStrLn "All past transactions succeeded... "+ Just end <- takeMVar blockNumberVar+ awaitBlock $ end + 1 -- make past transactions definitively in past+ var' <- newMVar []+ fiber' <- web3 $ do+ let fltr' = (def :: Filter EvT_CountSet) { filterAddress = Just [storage]+ , filterFromBlock = BlockWithNumber start}+ forkWeb3 $ processUntil' var' fltr' ((6 ==) . length)+ putStrLn "Setting more values"+ setValues storage theSets2+ wait fiber'+ putStrLn "All new values have ben set"+ vals <- takeMVar var'+ sort (unEvT_CountSet <$> vals) `shouldBe` sort (theSets1 <> theSets2) - it "can stream events starting and ending in the past, bounded" $ \primaryAccount -> do- runWeb3Configured Eth.blockNumber >>= \bn -> awaitBlock (bn + 1)+ it "can stream events starting and ending in the past, bounded" $ \storage -> do var <- newMVar []- let theCall = callFromTo primaryAccount contractAddress- theSets = [4, 5, 6]- start <- runWeb3Configured Eth.blockNumber+ let theSets = [4, 5, 6]+ start <- web3 Eth.blockNumber blockNumberVar <- newEmptyMVar- let fltr = (def :: Filter CountSet) { filterAddress = Just [contractAddress] }- print "Setting up filter for past transactions..."- fiber <- runWeb3Configured' $ do+ let fltr = (def :: Filter EvT_CountSet) { filterAddress = Just [storage] }+ putStrLn "Setting up filter for past transactions..."+ fiber <- web3 $ do forkWeb3 $ processUntil var fltr ((3 ==) . length) (liftIO . putMVar blockNumberVar . changeBlockNumber)- print "Setting values"- setValues theCall theSets+ putStrLn "Setting values"+ setValues storage theSets wait fiber- print "All values have been set"+ putStrLn "All values have been set" Just end <- takeMVar blockNumberVar var' <- newMVar [] let fltr' = fltr { filterFromBlock = BlockWithNumber start , filterToBlock = BlockWithNumber end } awaitBlock $ end + 1 -- make it definitively in the past- runWeb3Configured $ processUntil' var' fltr' ((3 ==) . length)+ web3 $ processUntil' var' fltr' ((3 ==) . length) vals <- takeMVar var'- sort (unCountSet <$> vals) `shouldBe` sort theSets+ sort (unEvT_CountSet <$> vals) `shouldBe` sort theSets -processUntil :: MVar [CountSet]- -> Filter CountSet- -> ([CountSet] -> Bool) -- TODO: make it work for any event+processUntil :: MVar [EvT_CountSet]+ -> Filter EvT_CountSet+ -> ([EvT_CountSet] -> Bool) -- TODO: make it work for any event -> (Change -> Web3 ()) -> Web3 ()-processUntil var filter predicate action = do- event' filter $ \(ev :: CountSet) -> do+processUntil var fltr predicate action = do+ event' fltr $ \(ev :: EvT_CountSet) -> do newV <- liftIO $ modifyMVar var $ \v -> return (ev:v, ev:v) if predicate newV then do@@ -194,13 +181,11 @@ return TerminateEvent else return ContinueEvent -processUntil' :: MVar [CountSet]- -> Filter CountSet- -> ([CountSet] -> Bool)+processUntil' :: MVar [EvT_CountSet]+ -> Filter EvT_CountSet+ -> ([EvT_CountSet] -> Bool) -> Web3 ()-processUntil' var filter predicate = processUntil var filter predicate (const $ return ())+processUntil' var fltr predicate = processUntil var fltr predicate (const $ return ()) -setValues :: Call -> [UIntN 256] -> IO ()-setValues theCall theSets = forM_ theSets $ \v -> do- runWeb3Configured (setCount theCall v)- threadDelay 1000000+setValues :: Address -> [UIntN 256] -> IO ()+setValues storage = mapM_ (contract storage . setCount)
test/Network/Ethereum/Web3/Test/Utils.hs view
@@ -1,92 +1,66 @@-{-# LANGUAGE LambdaCase #-}-module Network.Ethereum.Web3.Test.Utils- ( injectExportedEnvironmentVariables- , runWeb3Configured- , runWeb3Configured'- , withAccounts- , withPrimaryEthereumAccount- , callFromTo- , sleepSeconds- , microtime- , awaitBlock- ) where--import Control.Concurrent (MVar, threadDelay,- tryTakeMVar)-import Control.Monad.IO.Class (liftIO)-import Data.Default-import Data.Either (isRight)-import Data.List.Split (splitOn)-import Data.Maybe (fromMaybe)-import Data.Ratio (numerator)-import Data.String (IsString, fromString)-import qualified Data.Text as T-import Data.Time.Clock.POSIX (getPOSIXTime)-import Data.Traversable (for)+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-} -import Network.Ethereum.ABI.Prim.Address (Address)-import Network.Ethereum.Web3.Eth (accounts, blockNumber)-import Network.Ethereum.Web3.Provider (Provider (..), Web3,- Web3Error, runWeb3')-import Network.Ethereum.Web3.Types (Call (..), Quantity)-import System.Environment (lookupEnv, setEnv)-import Test.Hspec.Expectations (shouldSatisfy)+module Network.Ethereum.Web3.Test.Utils where -rpcUri :: IO String-rpcUri = liftIO (fromMaybe "http://localhost:8545" <$> lookupEnv "WEB3_PROVIDER")+import Control.Concurrent (threadDelay)+import Control.Exception (SomeException, catch)+import Control.Monad.IO.Class (liftIO)+import Data.Maybe (fromMaybe)+import Data.Ratio (numerator)+import Data.Time.Clock.POSIX (getPOSIXTime)+import Lens.Micro ((.~))+import Network.HTTP.Client (Manager, defaultManagerSettings,+ managerConnCount,+ managerRawConnection,+ managerRetryableException,+ newManager)+import System.Environment (lookupEnv)+import System.IO.Unsafe (unsafePerformIO) -exportStore :: String-exportStore = "./test-support/.detected-contract-addresses"+import Data.Solidity.Prim.Address (Address)+import Network.Ethereum.Account (DefaultAccount, to, withAccount,+ withParam)+import Network.Ethereum.Api.Eth (accounts, blockNumber)+import Network.Ethereum.Api.Provider (Provider (..), Web3,+ runWeb3With)+import Network.Ethereum.Api.Types (Quantity) -loadExportedEnvironmentVariables :: IO [(String, String)]-loadExportedEnvironmentVariables = do- exportables <- lines <$> readFile exportStore- detecteds <- for exportables $ \line -> case words line of- ["export", e] -> case splitOn "=" e of- [x] -> detectedEnv x ""- [k, v] -> detectedEnv k v- _ -> warnMalformation $ "oddly structured export statement " ++ line- _ -> warnMalformation $ "no export in line " ++ line- return $ concat detecteds+-- shared manager used throughout the helpers here to prevent hammering geth from ruining everything+-- this also retrys on ALL exceptions, including ConnectionResetByPeer and stuff like that+sharedManager :: Manager+sharedManager = unsafePerformIO $ newManager defaultManagerSettings+ { managerConnCount = 5+ , managerRetryableException = const False+ , managerRawConnection = fixRawConnection retryOpenConnection+ } - where warnMalformation m = do- putStrLn $ m ++ ". are you sure you're using the right inject-contract-addresses.sh?"- pure []- detectedEnv k v = do- -- putStrLn $ "detected " ++ k ++ "=" ++ v- pure [(k, v)]+ where retryOpenConnection = threadDelay 500000 >> managerRawConnection defaultManagerSettings+ fixRawConnection f = f `catch` (\(_ :: SomeException) -> fixRawConnection f)+{-# NOINLINE sharedManager #-} -injectExportedEnvironmentVariables :: IO ()-injectExportedEnvironmentVariables = do- detectedEnvs <- loadExportedEnvironmentVariables- sequence_ (uncurry setEnv <$> detectedEnvs)+rpcUri :: IO String+rpcUri = liftIO (fromMaybe "http://localhost:8545" <$> lookupEnv "WEB3_PROVIDER") -runWeb3Configured :: Show a => Web3 a -> IO a-runWeb3Configured f = do- provider <- HttpProvider <$> rpcUri- v <- runWeb3' provider f- v `shouldSatisfy` isRight- let Right a = v in return a+contract :: Address+ -> DefaultAccount Web3 a+ -> IO a+contract a = web3 . withAccount () . withParam (to .~ a) -runWeb3Configured' :: Web3 a -> IO a-runWeb3Configured' f = do+web3 :: Web3 a -> IO a+web3 ma = do provider <- HttpProvider <$> rpcUri- Right v <- runWeb3' provider f- return v+ v <- runWeb3With sharedManager provider ma+ case v of+ Left e -> print e >> threadDelay 1000000 >> web3 ma+ Right v' -> return v' withAccounts :: ([Address] -> IO a) -> IO a-withAccounts f = runWeb3Configured accounts >>= f+withAccounts f = web3 accounts >>= f withPrimaryEthereumAccount :: IO Address withPrimaryEthereumAccount = withAccounts (pure . head) -callFromTo :: Address -> Address -> Call-callFromTo from to =- def { callFrom = Just from- , callTo = Just to- , callGasPrice = Just 4000000000- }- sleepSeconds :: Int -> IO () sleepSeconds = threadDelay . (* 1000000) @@ -95,8 +69,13 @@ awaitBlock :: Quantity -> IO () awaitBlock bn = do- bn' <- runWeb3Configured blockNumber- putStrLn $ "awaiting block " ++ show bn ++ ", currently " ++ show bn'+ bn' <- web3 blockNumber+ -- putStrLn $ "awaiting block " ++ show bn ++ ", currently " ++ show bn' if bn' >= bn then return () else threadDelay 1000000 >> awaitBlock bn++sleepBlocks :: Int -> IO ()+sleepBlocks n = do+ now <- web3 blockNumber+ awaitBlock $ now + fromIntegral n
+ test/contracts/ComplexStorage.json view
@@ -0,0 +1,4533 @@+{+ "contractName": "ComplexStorage",+ "abi": [+ {+ "constant": true,+ "inputs": [],+ "name": "boolVal",+ "outputs": [+ {+ "name": "",+ "type": "bool"+ }+ ],+ "payable": false,+ "stateMutability": "view",+ "type": "function"+ },+ {+ "constant": true,+ "inputs": [],+ "name": "stringVal",+ "outputs": [+ {+ "name": "",+ "type": "string"+ }+ ],+ "payable": false,+ "stateMutability": "view",+ "type": "function"+ },+ {+ "constant": true,+ "inputs": [],+ "name": "intVal",+ "outputs": [+ {+ "name": "",+ "type": "int256"+ }+ ],+ "payable": false,+ "stateMutability": "view",+ "type": "function"+ },+ {+ "constant": true,+ "inputs": [+ {+ "name": "",+ "type": "uint256"+ }+ ],+ "name": "intListVal",+ "outputs": [+ {+ "name": "",+ "type": "int256"+ }+ ],+ "payable": false,+ "stateMutability": "view",+ "type": "function"+ },+ {+ "constant": true,+ "inputs": [],+ "name": "uintVal",+ "outputs": [+ {+ "name": "",+ "type": "uint256"+ }+ ],+ "payable": false,+ "stateMutability": "view",+ "type": "function"+ },+ {+ "constant": true,+ "inputs": [],+ "name": "int224Val",+ "outputs": [+ {+ "name": "",+ "type": "int224"+ }+ ],+ "payable": false,+ "stateMutability": "view",+ "type": "function"+ },+ {+ "constant": true,+ "inputs": [],+ "name": "bytes16Val",+ "outputs": [+ {+ "name": "",+ "type": "bytes16"+ }+ ],+ "payable": false,+ "stateMutability": "view",+ "type": "function"+ },+ {+ "constant": true,+ "inputs": [+ {+ "name": "",+ "type": "uint256"+ }+ ],+ "name": "boolVectorVal",+ "outputs": [+ {+ "name": "",+ "type": "bool"+ }+ ],+ "payable": false,+ "stateMutability": "view",+ "type": "function"+ },+ {+ "constant": true,+ "inputs": [+ {+ "name": "",+ "type": "uint256"+ },+ {+ "name": "",+ "type": "uint256"+ }+ ],+ "name": "bytes2VectorListVal",+ "outputs": [+ {+ "name": "",+ "type": "bytes2"+ }+ ],+ "payable": false,+ "stateMutability": "view",+ "type": "function"+ },+ {+ "anonymous": false,+ "inputs": [+ {+ "indexed": false,+ "name": "a",+ "type": "uint256"+ },+ {+ "indexed": false,+ "name": "b",+ "type": "int256"+ },+ {+ "indexed": false,+ "name": "c",+ "type": "bool"+ },+ {+ "indexed": false,+ "name": "d",+ "type": "int224"+ },+ {+ "indexed": false,+ "name": "e",+ "type": "bool[2]"+ },+ {+ "indexed": false,+ "name": "f",+ "type": "int256[]"+ },+ {+ "indexed": false,+ "name": "g",+ "type": "string"+ },+ {+ "indexed": false,+ "name": "h",+ "type": "bytes16"+ },+ {+ "indexed": false,+ "name": "i",+ "type": "bytes2[4][]"+ }+ ],+ "name": "ValsSet",+ "type": "event"+ },+ {+ "constant": false,+ "inputs": [+ {+ "name": "_uintVal",+ "type": "uint256"+ },+ {+ "name": "_intVal",+ "type": "int256"+ },+ {+ "name": "_boolVal",+ "type": "bool"+ },+ {+ "name": "_int224Val",+ "type": "int224"+ },+ {+ "name": "_boolVectorVal",+ "type": "bool[2]"+ },+ {+ "name": "_intListVal",+ "type": "int256[]"+ },+ {+ "name": "_stringVal",+ "type": "string"+ },+ {+ "name": "_bytes16Val",+ "type": "bytes16"+ },+ {+ "name": "_bytes2VectorListVal",+ "type": "bytes2[4][]"+ }+ ],+ "name": "setValues",+ "outputs": [],+ "payable": false,+ "stateMutability": "nonpayable",+ "type": "function"+ },+ {+ "constant": true,+ "inputs": [],+ "name": "getVals",+ "outputs": [+ {+ "name": "",+ "type": "uint256"+ },+ {+ "name": "",+ "type": "int256"+ },+ {+ "name": "",+ "type": "bool"+ },+ {+ "name": "",+ "type": "int224"+ },+ {+ "name": "",+ "type": "bool[2]"+ },+ {+ "name": "",+ "type": "int256[]"+ },+ {+ "name": "",+ "type": "string"+ },+ {+ "name": "",+ "type": "bytes16"+ },+ {+ "name": "",+ "type": "bytes2[4][]"+ }+ ],+ "payable": false,+ "stateMutability": "view",+ "type": "function"+ }+ ],+ "bytecode": "0x608060405234801561001057600080fd5b506111be806100206000396000f3006080604052600436106100af576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680631aadfbdb146100b45780632316afea14610258578063579c738a14610287578063614ac7911461031757806382a35c77146104dc5780638ba27dca146105075780639a0283ed146105485780639d49a304146105735780639eb7a6b2146105a4578063c84a4100146105f5578063f4f67ad71461063a575b600080fd5b3480156100c057600080fd5b5061025660048036038101908080359060200190929190803590602001909291908035151590602001909291908035601b0b9060200190929190806040019060028060200260405190810160405280929190826002602002808284378201915050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509192919290803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929080356fffffffffffffffffffffffffffffffff1916906020019092919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156102445784848390506080020160048060200260405190810160405280929190826004602002808284378201915050505050815260200190600101906101ff565b505050505091929192905050506106c7565b005b34801561026457600080fd5b5061026d6109b9565b604051808215151515815260200191505060405180910390f35b34801561029357600080fd5b5061029c6109cc565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156102dc5780820151818401526020810190506102c1565b50505050905090810190601f1680156103095780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561032357600080fd5b5061032c610a6a565b604051808a81526020018981526020018815151515815260200187601b0b601b0b815260200186600260200280838360005b8381101561037957808201518184015260208101905061035e565b505050509050018060200180602001856fffffffffffffffffffffffffffffffff19166fffffffffffffffffffffffffffffffff1916815260200180602001848103845288818151815260200191508051906020019060200280838360005b838110156103f35780820151818401526020810190506103d8565b50505050905001848103835287818151815260200191508051906020019080838360005b83811015610432578082015181840152602081019050610417565b50505050905090810190601f16801561045f5780820380516001836020036101000a031916815260200191505b508481038252858181518152602001915080516000925b818410156104c157828490602001906020020151600460200280838360005b838110156104b0578082015181840152602081019050610495565b505050509050019260010192610476565b925050509c5050505050505050505050505060405180910390f35b3480156104e857600080fd5b506104f1610d24565b6040518082815260200191505060405180910390f35b34801561051357600080fd5b5061053260048036038101908080359060200190929190505050610d2a565b6040518082815260200191505060405180910390f35b34801561055457600080fd5b5061055d610d4d565b6040518082815260200191505060405180910390f35b34801561057f57600080fd5b50610588610d53565b6040518082601b0b601b0b815260200191505060405180910390f35b3480156105b057600080fd5b506105b9610d66565b60405180826fffffffffffffffffffffffffffffffff19166fffffffffffffffffffffffffffffffff1916815260200191505060405180910390f35b34801561060157600080fd5b5061062060048036038101908080359060200190929190505050610d89565b604051808215151515815260200191505060405180910390f35b34801561064657600080fd5b5061066f6004803603810190808035906020019092919080359060200190929190505050610db2565b60405180827dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200191505060405180910390f35b886000819055508760018190555086600260006101000a81548160ff02191690831515021790555085600260016101000a8154817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff0219169083601b0b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff160217905550846003906002610754929190610e16565b50836004908051906020019061076b929190610eaf565b508260059080519060200190610782929190610efc565b5081600660006101000a8154816fffffffffffffffffffffffffffffffff02191690837001000000000000000000000000000000009004021790555080600790805190602001906107d4929190610f7c565b507f88d23351ad32a937b11ca10530404f8297d29803e94709336b48c1f82c15b3cc898989898989898989604051808a81526020018981526020018815151515815260200187601b0b601b0b815260200186600260200280838360005b8381101561084c578082015181840152602081019050610831565b505050509050018060200180602001856fffffffffffffffffffffffffffffffff19166fffffffffffffffffffffffffffffffff1916815260200180602001848103845288818151815260200191508051906020019060200280838360005b838110156108c65780820151818401526020810190506108ab565b50505050905001848103835287818151815260200191508051906020019080838360005b838110156109055780820151818401526020810190506108ea565b50505050905090810190601f1680156109325780820380516001836020036101000a031916815260200191505b508481038252858181518152602001915080516000925b8184101561099457828490602001906020020151600460200280838360005b83811015610983578082015181840152602081019050610968565b505050509050019260010192610949565b925050509c5050505050505050505050505060405180910390a1505050505050505050565b600260009054906101000a900460ff1681565b60058054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610a625780601f10610a3757610100808354040283529160200191610a62565b820191906000526020600020905b815481529060010190602001808311610a4557829003601f168201915b505050505081565b600080600080610a78610fd7565b60608060006060600054600154600260009054906101000a900460ff16600260019054906101000a9004601b0b600360046005600660009054906101000a900470010000000000000000000000000000000002600784600280602002604051908101604052809291908260028015610b2a576020028201916000905b82829054906101000a900460ff16151581526020019060010190602082600001049283019260010382029150808411610af45790505b5050505050945083805480602002602001604051908101604052809291908181526020018280548015610b7c57602002820191906000526020600020905b815481526020019060010190808311610b68575b50505050509350828054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610c185780601f10610bed57610100808354040283529160200191610c18565b820191906000526020600020905b815481529060010190602001808311610bfb57829003601f168201915b5050505050925080805480602002602001604051908101604052809291908181526020016000905b82821015610d0157838290600052602060002001600480602002604051908101604052809291908260048015610ced576020028201916000905b82829054906101000a90047e01000000000000000000000000000000000000000000000000000000000000027dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019060020190602082600101049283019260010382029150808411610c7a5790505b505050505081526020019060010190610c40565b505050509050985098509850985098509850985098509850909192939495969798565b60015481565b600481815481101515610d3957fe5b906000526020600020016000915090505481565b60005481565b600260019054906101000a9004601b0b81565b600660009054906101000a90047001000000000000000000000000000000000281565b600381600281101515610d9857fe5b60209182820401919006915054906101000a900460ff1681565b600782815481101515610dc157fe5b9060005260206000200181600481101515610dd857fe5b60109182820401919006600202915091509054906101000a90047e010000000000000000000000000000000000000000000000000000000000000281565b826002601f01602090048101928215610e9e5791602002820160005b83821115610e6f57835183826101000a81548160ff0219169083151502179055509260200192600101602081600001049283019260010302610e32565b8015610e9c5782816101000a81549060ff0219169055600101602081600001049283019260010302610e6f565b505b509050610eab9190610ff9565b5090565b828054828255906000526020600020908101928215610eeb579160200282015b82811115610eea578251825591602001919060010190610ecf565b5b509050610ef89190611029565b5090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10610f3d57805160ff1916838001178555610f6b565b82800160010185558215610f6b579182015b82811115610f6a578251825591602001919060010190610f4f565b5b509050610f78919061104e565b5090565b828054828255906000526020600020908101928215610fc6579160200282015b82811115610fc557825182906004610fb5929190611073565b5091602001919060010190610f9c565b5b509050610fd3919061112e565b5090565b6040805190810160405280600290602082028038833980820191505090505090565b61102691905b8082111561102257600081816101000a81549060ff021916905550600101610fff565b5090565b90565b61104b91905b8082111561104757600081600090555060010161102f565b5090565b90565b61107091905b8082111561106c576000816000905550600101611054565b5090565b90565b826004600f0160109004810192821561111d5791602002820160005b838211156110ed57835183826101000a81548161ffff02191690837e0100000000000000000000000000000000000000000000000000000000000090040217905550926020019260020160208160010104928301926001030261108f565b801561111b5782816101000a81549061ffff02191690556002016020816001010492830192600103026110ed565b505b50905061112a919061115a565b5090565b61115791905b80821115611153576000818161114a919061118b565b50600101611134565b5090565b90565b61118891905b8082111561118457600081816101000a81549061ffff021916905550600101611160565b5090565b90565b50600090555600a165627a7a7230582011b9a8b2fe6341272836fb36535a5f03b46544a58a14b17b7d49405a8247b7d10029",+ "deployedBytecode": "0x6080604052600436106100af576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680631aadfbdb146100b45780632316afea14610258578063579c738a14610287578063614ac7911461031757806382a35c77146104dc5780638ba27dca146105075780639a0283ed146105485780639d49a304146105735780639eb7a6b2146105a4578063c84a4100146105f5578063f4f67ad71461063a575b600080fd5b3480156100c057600080fd5b5061025660048036038101908080359060200190929190803590602001909291908035151590602001909291908035601b0b9060200190929190806040019060028060200260405190810160405280929190826002602002808284378201915050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509192919290803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929080356fffffffffffffffffffffffffffffffff1916906020019092919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156102445784848390506080020160048060200260405190810160405280929190826004602002808284378201915050505050815260200190600101906101ff565b505050505091929192905050506106c7565b005b34801561026457600080fd5b5061026d6109b9565b604051808215151515815260200191505060405180910390f35b34801561029357600080fd5b5061029c6109cc565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156102dc5780820151818401526020810190506102c1565b50505050905090810190601f1680156103095780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561032357600080fd5b5061032c610a6a565b604051808a81526020018981526020018815151515815260200187601b0b601b0b815260200186600260200280838360005b8381101561037957808201518184015260208101905061035e565b505050509050018060200180602001856fffffffffffffffffffffffffffffffff19166fffffffffffffffffffffffffffffffff1916815260200180602001848103845288818151815260200191508051906020019060200280838360005b838110156103f35780820151818401526020810190506103d8565b50505050905001848103835287818151815260200191508051906020019080838360005b83811015610432578082015181840152602081019050610417565b50505050905090810190601f16801561045f5780820380516001836020036101000a031916815260200191505b508481038252858181518152602001915080516000925b818410156104c157828490602001906020020151600460200280838360005b838110156104b0578082015181840152602081019050610495565b505050509050019260010192610476565b925050509c5050505050505050505050505060405180910390f35b3480156104e857600080fd5b506104f1610d24565b6040518082815260200191505060405180910390f35b34801561051357600080fd5b5061053260048036038101908080359060200190929190505050610d2a565b6040518082815260200191505060405180910390f35b34801561055457600080fd5b5061055d610d4d565b6040518082815260200191505060405180910390f35b34801561057f57600080fd5b50610588610d53565b6040518082601b0b601b0b815260200191505060405180910390f35b3480156105b057600080fd5b506105b9610d66565b60405180826fffffffffffffffffffffffffffffffff19166fffffffffffffffffffffffffffffffff1916815260200191505060405180910390f35b34801561060157600080fd5b5061062060048036038101908080359060200190929190505050610d89565b604051808215151515815260200191505060405180910390f35b34801561064657600080fd5b5061066f6004803603810190808035906020019092919080359060200190929190505050610db2565b60405180827dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200191505060405180910390f35b886000819055508760018190555086600260006101000a81548160ff02191690831515021790555085600260016101000a8154817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff0219169083601b0b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff160217905550846003906002610754929190610e16565b50836004908051906020019061076b929190610eaf565b508260059080519060200190610782929190610efc565b5081600660006101000a8154816fffffffffffffffffffffffffffffffff02191690837001000000000000000000000000000000009004021790555080600790805190602001906107d4929190610f7c565b507f88d23351ad32a937b11ca10530404f8297d29803e94709336b48c1f82c15b3cc898989898989898989604051808a81526020018981526020018815151515815260200187601b0b601b0b815260200186600260200280838360005b8381101561084c578082015181840152602081019050610831565b505050509050018060200180602001856fffffffffffffffffffffffffffffffff19166fffffffffffffffffffffffffffffffff1916815260200180602001848103845288818151815260200191508051906020019060200280838360005b838110156108c65780820151818401526020810190506108ab565b50505050905001848103835287818151815260200191508051906020019080838360005b838110156109055780820151818401526020810190506108ea565b50505050905090810190601f1680156109325780820380516001836020036101000a031916815260200191505b508481038252858181518152602001915080516000925b8184101561099457828490602001906020020151600460200280838360005b83811015610983578082015181840152602081019050610968565b505050509050019260010192610949565b925050509c5050505050505050505050505060405180910390a1505050505050505050565b600260009054906101000a900460ff1681565b60058054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610a625780601f10610a3757610100808354040283529160200191610a62565b820191906000526020600020905b815481529060010190602001808311610a4557829003601f168201915b505050505081565b600080600080610a78610fd7565b60608060006060600054600154600260009054906101000a900460ff16600260019054906101000a9004601b0b600360046005600660009054906101000a900470010000000000000000000000000000000002600784600280602002604051908101604052809291908260028015610b2a576020028201916000905b82829054906101000a900460ff16151581526020019060010190602082600001049283019260010382029150808411610af45790505b5050505050945083805480602002602001604051908101604052809291908181526020018280548015610b7c57602002820191906000526020600020905b815481526020019060010190808311610b68575b50505050509350828054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610c185780601f10610bed57610100808354040283529160200191610c18565b820191906000526020600020905b815481529060010190602001808311610bfb57829003601f168201915b5050505050925080805480602002602001604051908101604052809291908181526020016000905b82821015610d0157838290600052602060002001600480602002604051908101604052809291908260048015610ced576020028201916000905b82829054906101000a90047e01000000000000000000000000000000000000000000000000000000000000027dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019060020190602082600101049283019260010382029150808411610c7a5790505b505050505081526020019060010190610c40565b505050509050985098509850985098509850985098509850909192939495969798565b60015481565b600481815481101515610d3957fe5b906000526020600020016000915090505481565b60005481565b600260019054906101000a9004601b0b81565b600660009054906101000a90047001000000000000000000000000000000000281565b600381600281101515610d9857fe5b60209182820401919006915054906101000a900460ff1681565b600782815481101515610dc157fe5b9060005260206000200181600481101515610dd857fe5b60109182820401919006600202915091509054906101000a90047e010000000000000000000000000000000000000000000000000000000000000281565b826002601f01602090048101928215610e9e5791602002820160005b83821115610e6f57835183826101000a81548160ff0219169083151502179055509260200192600101602081600001049283019260010302610e32565b8015610e9c5782816101000a81549060ff0219169055600101602081600001049283019260010302610e6f565b505b509050610eab9190610ff9565b5090565b828054828255906000526020600020908101928215610eeb579160200282015b82811115610eea578251825591602001919060010190610ecf565b5b509050610ef89190611029565b5090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10610f3d57805160ff1916838001178555610f6b565b82800160010185558215610f6b579182015b82811115610f6a578251825591602001919060010190610f4f565b5b509050610f78919061104e565b5090565b828054828255906000526020600020908101928215610fc6579160200282015b82811115610fc557825182906004610fb5929190611073565b5091602001919060010190610f9c565b5b509050610fd3919061112e565b5090565b6040805190810160405280600290602082028038833980820191505090505090565b61102691905b8082111561102257600081816101000a81549060ff021916905550600101610fff565b5090565b90565b61104b91905b8082111561104757600081600090555060010161102f565b5090565b90565b61107091905b8082111561106c576000816000905550600101611054565b5090565b90565b826004600f0160109004810192821561111d5791602002820160005b838211156110ed57835183826101000a81548161ffff02191690837e0100000000000000000000000000000000000000000000000000000000000090040217905550926020019260020160208160010104928301926001030261108f565b801561111b5782816101000a81549061ffff02191690556002016020816001010492830192600103026110ed565b505b50905061112a919061115a565b5090565b61115791905b80821115611153576000818161114a919061118b565b50600101611134565b5090565b90565b61118891905b8082111561118457600081816101000a81549061ffff021916905550600101611160565b5090565b90565b50600090555600a165627a7a7230582011b9a8b2fe6341272836fb36535a5f03b46544a58a14b17b7d49405a8247b7d10029",+ "sourceMap": "26:1413:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;26:1413:0;;;;;;;",+ "deployedSourceMap": "26:1413:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;439:742;;8:9:-1;5:2;;;30:1;27;20:12;5:2;439:742:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;104:19;;8:9:-1;5:2;;;30:1;27;20:12;5:2;104:19:0;;;;;;;;;;;;;;;;;;;;;;;;;;;221:23;;8:9:-1;5:2;;;30:1;27;20:12;5:2;221:23:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;221:23:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1187:246;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1187:246:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;1187:246:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;1187:246:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;1187:246:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;1187:246:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;81:17;;8:9:-1;5:2;;;30:1;27;20:12;5:2;81:17:0;;;;;;;;;;;;;;;;;;;;;;;192:23;;8:9:-1;5:2;;;30:1;27;20:12;5:2;192:23:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;56:19;;8:9:-1;5:2;;;30:1;27;20:12;5:2;56:19:0;;;;;;;;;;;;;;;;;;;;;;;129:23;;8:9:-1;5:2;;;30:1;27;20:12;5:2;129:23:0;;;;;;;;;;;;;;;;;;;;;;;;;;;250:25;;8:9:-1;5:2;;;30:1;27;20:12;5:2;250:25:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;158:28;;8:9:-1;5:2;;;30:1;27;20:12;5:2;158:28:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;281:38;;8:9:-1;5:2;;;30:1;27;20:12;5:2;281:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;439:742;675:8;655:7;:28;;;;714:7;694:6;:27;;;;752:8;732:7;;:28;;;;;;;;;;;;;;;;;;791:10;771:9;;:30;;;;;;;;;;;;;;;;;;;;832:14;812:13;:34;;;;;;;:::i;:::-;;877:11;857:10;:31;;;;;;;;;;;;:::i;:::-;;919:10;899:9;:30;;;;;;;;;;;;:::i;:::-;;960:11;940:10;;:31;;;;;;;;;;;;;;;;;;;1004:20;982:19;:42;;;;;;;;;;;;:::i;:::-;;1050:124;1058:8;1068:7;1077:8;1087:10;1099:14;1115:11;1128:10;1140:11;1153:20;1050:124;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;1050:124:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;1050:124:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;1050:124:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;1050:124:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;439:742;;;;;;;;;:::o;104:19::-;;;;;;;;;;;;;:::o;221:23::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;1187:246::-;1232:4;1238:3;1243:4;1249:6;1257:7;;:::i;:::-;1266:5;1273:6;1281:7;1290:11;1319:7;;1328:6;;1336:7;;;;;;;;;;;1345:9;;;;;;;;;;;1356:13;1371:10;1383:9;1394:10;;;;;;;;;;;1406:19;1311:115;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1187:246;;;;;;;;;:::o;81:17::-;;;;:::o;192:23::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;56:19::-;;;;:::o;129:23::-;;;;;;;;;;;;;:::o;250:25::-;;;;;;;;;;;;;:::o;158:28::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;281:38::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;26:1413::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;148:4;140:6;136:17;126:27;;0:157;26:1413:0;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;:::o",+ "source": "pragma solidity ^0.4.13;\n\ncontract ComplexStorage {\n uint public uintVal;\n int public intVal;\n bool public boolVal;\n int224 public int224Val;\n bool[2] public boolVectorVal;\n int[] public intListVal;\n string public stringVal;\n bytes16 public bytes16Val;\n bytes2[4][] public bytes2VectorListVal;\n\n event ValsSet(uint a, int b, bool c, int224 d, bool[2] e, int[] f, string g, bytes16 h, bytes2[4][] i);\n \n function setValues(uint _uintVal, int _intVal, bool _boolVal, int224 _int224Val, bool[2] _boolVectorVal, int[] _intListVal, string _stringVal, bytes16 _bytes16Val, bytes2[4][] _bytes2VectorListVal) public {\n uintVal = _uintVal;\n intVal = _intVal;\n boolVal = _boolVal;\n int224Val = _int224Val;\n boolVectorVal = _boolVectorVal;\n intListVal = _intListVal;\n stringVal = _stringVal;\n bytes16Val = _bytes16Val;\n bytes2VectorListVal = _bytes2VectorListVal;\n \n emit ValsSet(_uintVal, _intVal, _boolVal, _int224Val, _boolVectorVal, _intListVal, _stringVal, _bytes16Val, _bytes2VectorListVal);\n }\n\n function getVals () constant public returns (uint, int, bool, int224, bool[2], int[], string, bytes16, bytes2[4][]) {\n return (uintVal, intVal, boolVal, int224Val, boolVectorVal, intListVal, stringVal, bytes16Val, bytes2VectorListVal);\n }\n \n}\n",+ "sourcePath": "/home/akru/hsweb3test/contracts/ComplexStorage.sol",+ "ast": {+ "absolutePath": "/home/akru/hsweb3test/contracts/ComplexStorage.sol",+ "exportedSymbols": {+ "ComplexStorage": [+ 167+ ]+ },+ "id": 168,+ "nodeType": "SourceUnit",+ "nodes": [+ {+ "id": 1,+ "literals": [+ "solidity",+ "^",+ "0.4",+ ".13"+ ],+ "nodeType": "PragmaDirective",+ "src": "0:24:0"+ },+ {+ "baseContracts": [],+ "contractDependencies": [],+ "contractKind": "contract",+ "documentation": null,+ "fullyImplemented": true,+ "id": 167,+ "linearizedBaseContracts": [+ 167+ ],+ "name": "ComplexStorage",+ "nodeType": "ContractDefinition",+ "nodes": [+ {+ "constant": false,+ "id": 3,+ "name": "uintVal",+ "nodeType": "VariableDeclaration",+ "scope": 167,+ "src": "56:19:0",+ "stateVariable": true,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ },+ "typeName": {+ "id": 2,+ "name": "uint",+ "nodeType": "ElementaryTypeName",+ "src": "56:4:0",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "value": null,+ "visibility": "public"+ },+ {+ "constant": false,+ "id": 5,+ "name": "intVal",+ "nodeType": "VariableDeclaration",+ "scope": 167,+ "src": "81:17:0",+ "stateVariable": true,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ },+ "typeName": {+ "id": 4,+ "name": "int",+ "nodeType": "ElementaryTypeName",+ "src": "81:3:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ }+ },+ "value": null,+ "visibility": "public"+ },+ {+ "constant": false,+ "id": 7,+ "name": "boolVal",+ "nodeType": "VariableDeclaration",+ "scope": 167,+ "src": "104:19:0",+ "stateVariable": true,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ },+ "typeName": {+ "id": 6,+ "name": "bool",+ "nodeType": "ElementaryTypeName",+ "src": "104:4:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ }+ },+ "value": null,+ "visibility": "public"+ },+ {+ "constant": false,+ "id": 9,+ "name": "int224Val",+ "nodeType": "VariableDeclaration",+ "scope": 167,+ "src": "129:23:0",+ "stateVariable": true,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_int224",+ "typeString": "int224"+ },+ "typeName": {+ "id": 8,+ "name": "int224",+ "nodeType": "ElementaryTypeName",+ "src": "129:6:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int224",+ "typeString": "int224"+ }+ },+ "value": null,+ "visibility": "public"+ },+ {+ "constant": false,+ "id": 13,+ "name": "boolVectorVal",+ "nodeType": "VariableDeclaration",+ "scope": 167,+ "src": "158:28:0",+ "stateVariable": true,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bool_$2_storage",+ "typeString": "bool[2]"+ },+ "typeName": {+ "baseType": {+ "id": 10,+ "name": "bool",+ "nodeType": "ElementaryTypeName",+ "src": "158:4:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ }+ },+ "id": 12,+ "length": {+ "argumentTypes": null,+ "hexValue": "32",+ "id": 11,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "number",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "163:1:0",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": null,+ "typeString": null+ },+ "value": "2"+ },+ "nodeType": "ArrayTypeName",+ "src": "158:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bool_$2_storage_ptr",+ "typeString": "bool[2]"+ }+ },+ "value": null,+ "visibility": "public"+ },+ {+ "constant": false,+ "id": 16,+ "name": "intListVal",+ "nodeType": "VariableDeclaration",+ "scope": 167,+ "src": "192:23:0",+ "stateVariable": true,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_int256_$dyn_storage",+ "typeString": "int256[]"+ },+ "typeName": {+ "baseType": {+ "id": 14,+ "name": "int",+ "nodeType": "ElementaryTypeName",+ "src": "192:3:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ }+ },+ "id": 15,+ "length": null,+ "nodeType": "ArrayTypeName",+ "src": "192:5:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_int256_$dyn_storage_ptr",+ "typeString": "int256[]"+ }+ },+ "value": null,+ "visibility": "public"+ },+ {+ "constant": false,+ "id": 18,+ "name": "stringVal",+ "nodeType": "VariableDeclaration",+ "scope": 167,+ "src": "221:23:0",+ "stateVariable": true,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_string_storage",+ "typeString": "string"+ },+ "typeName": {+ "id": 17,+ "name": "string",+ "nodeType": "ElementaryTypeName",+ "src": "221:6:0",+ "typeDescriptions": {+ "typeIdentifier": "t_string_storage_ptr",+ "typeString": "string"+ }+ },+ "value": null,+ "visibility": "public"+ },+ {+ "constant": false,+ "id": 20,+ "name": "bytes16Val",+ "nodeType": "VariableDeclaration",+ "scope": 167,+ "src": "250:25:0",+ "stateVariable": true,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes16",+ "typeString": "bytes16"+ },+ "typeName": {+ "id": 19,+ "name": "bytes16",+ "nodeType": "ElementaryTypeName",+ "src": "250:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes16",+ "typeString": "bytes16"+ }+ },+ "value": null,+ "visibility": "public"+ },+ {+ "constant": false,+ "id": 25,+ "name": "bytes2VectorListVal",+ "nodeType": "VariableDeclaration",+ "scope": 167,+ "src": "281:38:0",+ "stateVariable": true,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_array$_t_bytes2_$4_storage_$dyn_storage",+ "typeString": "bytes2[4][]"+ },+ "typeName": {+ "baseType": {+ "baseType": {+ "id": 21,+ "name": "bytes2",+ "nodeType": "ElementaryTypeName",+ "src": "281:6:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes2",+ "typeString": "bytes2"+ }+ },+ "id": 23,+ "length": {+ "argumentTypes": null,+ "hexValue": "34",+ "id": 22,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "number",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "288:1:0",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": null,+ "typeString": null+ },+ "value": "4"+ },+ "nodeType": "ArrayTypeName",+ "src": "281:9:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bytes2_$4_storage_ptr",+ "typeString": "bytes2[4]"+ }+ },+ "id": 24,+ "length": null,+ "nodeType": "ArrayTypeName",+ "src": "281:11:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_array$_t_bytes2_$4_storage_$dyn_storage_ptr",+ "typeString": "bytes2[4][]"+ }+ },+ "value": null,+ "visibility": "public"+ },+ {+ "anonymous": false,+ "documentation": null,+ "id": 51,+ "name": "ValsSet",+ "nodeType": "EventDefinition",+ "parameters": {+ "id": 50,+ "nodeType": "ParameterList",+ "parameters": [+ {+ "constant": false,+ "id": 27,+ "indexed": false,+ "name": "a",+ "nodeType": "VariableDeclaration",+ "scope": 51,+ "src": "340:6:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ },+ "typeName": {+ "id": 26,+ "name": "uint",+ "nodeType": "ElementaryTypeName",+ "src": "340:4:0",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 29,+ "indexed": false,+ "name": "b",+ "nodeType": "VariableDeclaration",+ "scope": 51,+ "src": "348:5:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ },+ "typeName": {+ "id": 28,+ "name": "int",+ "nodeType": "ElementaryTypeName",+ "src": "348:3:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 31,+ "indexed": false,+ "name": "c",+ "nodeType": "VariableDeclaration",+ "scope": 51,+ "src": "355:6:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ },+ "typeName": {+ "id": 30,+ "name": "bool",+ "nodeType": "ElementaryTypeName",+ "src": "355:4:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 33,+ "indexed": false,+ "name": "d",+ "nodeType": "VariableDeclaration",+ "scope": 51,+ "src": "363:8:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_int224",+ "typeString": "int224"+ },+ "typeName": {+ "id": 32,+ "name": "int224",+ "nodeType": "ElementaryTypeName",+ "src": "363:6:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int224",+ "typeString": "int224"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 37,+ "indexed": false,+ "name": "e",+ "nodeType": "VariableDeclaration",+ "scope": 51,+ "src": "373:9:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bool_$2_memory_ptr",+ "typeString": "bool[2]"+ },+ "typeName": {+ "baseType": {+ "id": 34,+ "name": "bool",+ "nodeType": "ElementaryTypeName",+ "src": "373:4:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ }+ },+ "id": 36,+ "length": {+ "argumentTypes": null,+ "hexValue": "32",+ "id": 35,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "number",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "378:1:0",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": null,+ "typeString": null+ },+ "value": "2"+ },+ "nodeType": "ArrayTypeName",+ "src": "373:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bool_$2_storage_ptr",+ "typeString": "bool[2]"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 40,+ "indexed": false,+ "name": "f",+ "nodeType": "VariableDeclaration",+ "scope": 51,+ "src": "384:7:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_int256_$dyn_memory_ptr",+ "typeString": "int256[]"+ },+ "typeName": {+ "baseType": {+ "id": 38,+ "name": "int",+ "nodeType": "ElementaryTypeName",+ "src": "384:3:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ }+ },+ "id": 39,+ "length": null,+ "nodeType": "ArrayTypeName",+ "src": "384:5:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_int256_$dyn_storage_ptr",+ "typeString": "int256[]"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 42,+ "indexed": false,+ "name": "g",+ "nodeType": "VariableDeclaration",+ "scope": 51,+ "src": "393:8:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_string_memory_ptr",+ "typeString": "string"+ },+ "typeName": {+ "id": 41,+ "name": "string",+ "nodeType": "ElementaryTypeName",+ "src": "393:6:0",+ "typeDescriptions": {+ "typeIdentifier": "t_string_storage_ptr",+ "typeString": "string"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 44,+ "indexed": false,+ "name": "h",+ "nodeType": "VariableDeclaration",+ "scope": 51,+ "src": "403:9:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes16",+ "typeString": "bytes16"+ },+ "typeName": {+ "id": 43,+ "name": "bytes16",+ "nodeType": "ElementaryTypeName",+ "src": "403:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes16",+ "typeString": "bytes16"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 49,+ "indexed": false,+ "name": "i",+ "nodeType": "VariableDeclaration",+ "scope": 51,+ "src": "414:13:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_array$_t_bytes2_$4_memory_$dyn_memory_ptr",+ "typeString": "bytes2[4][]"+ },+ "typeName": {+ "baseType": {+ "baseType": {+ "id": 45,+ "name": "bytes2",+ "nodeType": "ElementaryTypeName",+ "src": "414:6:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes2",+ "typeString": "bytes2"+ }+ },+ "id": 47,+ "length": {+ "argumentTypes": null,+ "hexValue": "34",+ "id": 46,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "number",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "421:1:0",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": null,+ "typeString": null+ },+ "value": "4"+ },+ "nodeType": "ArrayTypeName",+ "src": "414:9:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bytes2_$4_storage_ptr",+ "typeString": "bytes2[4]"+ }+ },+ "id": 48,+ "length": null,+ "nodeType": "ArrayTypeName",+ "src": "414:11:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_array$_t_bytes2_$4_storage_$dyn_storage_ptr",+ "typeString": "bytes2[4][]"+ }+ },+ "value": null,+ "visibility": "internal"+ }+ ],+ "src": "339:89:0"+ },+ "src": "326:103:0"+ },+ {+ "body": {+ "id": 126,+ "nodeType": "Block",+ "src": "644:537:0",+ "statements": [+ {+ "expression": {+ "argumentTypes": null,+ "id": 80,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "leftHandSide": {+ "argumentTypes": null,+ "id": 78,+ "name": "uintVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 3,+ "src": "655:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "nodeType": "Assignment",+ "operator": "=",+ "rightHandSide": {+ "argumentTypes": null,+ "id": 79,+ "name": "_uintVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 53,+ "src": "675:8:0",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "src": "655:28:0",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "id": 81,+ "nodeType": "ExpressionStatement",+ "src": "655:28:0"+ },+ {+ "expression": {+ "argumentTypes": null,+ "id": 84,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "leftHandSide": {+ "argumentTypes": null,+ "id": 82,+ "name": "intVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 5,+ "src": "694:6:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ }+ },+ "nodeType": "Assignment",+ "operator": "=",+ "rightHandSide": {+ "argumentTypes": null,+ "id": 83,+ "name": "_intVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 55,+ "src": "714:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ }+ },+ "src": "694:27:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ }+ },+ "id": 85,+ "nodeType": "ExpressionStatement",+ "src": "694:27:0"+ },+ {+ "expression": {+ "argumentTypes": null,+ "id": 88,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "leftHandSide": {+ "argumentTypes": null,+ "id": 86,+ "name": "boolVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 7,+ "src": "732:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ }+ },+ "nodeType": "Assignment",+ "operator": "=",+ "rightHandSide": {+ "argumentTypes": null,+ "id": 87,+ "name": "_boolVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 57,+ "src": "752:8:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ }+ },+ "src": "732:28:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ }+ },+ "id": 89,+ "nodeType": "ExpressionStatement",+ "src": "732:28:0"+ },+ {+ "expression": {+ "argumentTypes": null,+ "id": 92,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "leftHandSide": {+ "argumentTypes": null,+ "id": 90,+ "name": "int224Val",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 9,+ "src": "771:9:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int224",+ "typeString": "int224"+ }+ },+ "nodeType": "Assignment",+ "operator": "=",+ "rightHandSide": {+ "argumentTypes": null,+ "id": 91,+ "name": "_int224Val",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 59,+ "src": "791:10:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int224",+ "typeString": "int224"+ }+ },+ "src": "771:30:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int224",+ "typeString": "int224"+ }+ },+ "id": 93,+ "nodeType": "ExpressionStatement",+ "src": "771:30:0"+ },+ {+ "expression": {+ "argumentTypes": null,+ "id": 96,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "leftHandSide": {+ "argumentTypes": null,+ "id": 94,+ "name": "boolVectorVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 13,+ "src": "812:13:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bool_$2_storage",+ "typeString": "bool[2] storage ref"+ }+ },+ "nodeType": "Assignment",+ "operator": "=",+ "rightHandSide": {+ "argumentTypes": null,+ "id": 95,+ "name": "_boolVectorVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 63,+ "src": "832:14:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bool_$2_memory_ptr",+ "typeString": "bool[2] memory"+ }+ },+ "src": "812:34:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bool_$2_storage",+ "typeString": "bool[2] storage ref"+ }+ },+ "id": 97,+ "nodeType": "ExpressionStatement",+ "src": "812:34:0"+ },+ {+ "expression": {+ "argumentTypes": null,+ "id": 100,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "leftHandSide": {+ "argumentTypes": null,+ "id": 98,+ "name": "intListVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 16,+ "src": "857:10:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_int256_$dyn_storage",+ "typeString": "int256[] storage ref"+ }+ },+ "nodeType": "Assignment",+ "operator": "=",+ "rightHandSide": {+ "argumentTypes": null,+ "id": 99,+ "name": "_intListVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 66,+ "src": "877:11:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_int256_$dyn_memory_ptr",+ "typeString": "int256[] memory"+ }+ },+ "src": "857:31:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_int256_$dyn_storage",+ "typeString": "int256[] storage ref"+ }+ },+ "id": 101,+ "nodeType": "ExpressionStatement",+ "src": "857:31:0"+ },+ {+ "expression": {+ "argumentTypes": null,+ "id": 104,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "leftHandSide": {+ "argumentTypes": null,+ "id": 102,+ "name": "stringVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 18,+ "src": "899:9:0",+ "typeDescriptions": {+ "typeIdentifier": "t_string_storage",+ "typeString": "string storage ref"+ }+ },+ "nodeType": "Assignment",+ "operator": "=",+ "rightHandSide": {+ "argumentTypes": null,+ "id": 103,+ "name": "_stringVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 68,+ "src": "919:10:0",+ "typeDescriptions": {+ "typeIdentifier": "t_string_memory_ptr",+ "typeString": "string memory"+ }+ },+ "src": "899:30:0",+ "typeDescriptions": {+ "typeIdentifier": "t_string_storage",+ "typeString": "string storage ref"+ }+ },+ "id": 105,+ "nodeType": "ExpressionStatement",+ "src": "899:30:0"+ },+ {+ "expression": {+ "argumentTypes": null,+ "id": 108,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "leftHandSide": {+ "argumentTypes": null,+ "id": 106,+ "name": "bytes16Val",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 20,+ "src": "940:10:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes16",+ "typeString": "bytes16"+ }+ },+ "nodeType": "Assignment",+ "operator": "=",+ "rightHandSide": {+ "argumentTypes": null,+ "id": 107,+ "name": "_bytes16Val",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 70,+ "src": "960:11:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes16",+ "typeString": "bytes16"+ }+ },+ "src": "940:31:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes16",+ "typeString": "bytes16"+ }+ },+ "id": 109,+ "nodeType": "ExpressionStatement",+ "src": "940:31:0"+ },+ {+ "expression": {+ "argumentTypes": null,+ "id": 112,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "leftHandSide": {+ "argumentTypes": null,+ "id": 110,+ "name": "bytes2VectorListVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 25,+ "src": "982:19:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_array$_t_bytes2_$4_storage_$dyn_storage",+ "typeString": "bytes2[4] storage ref[] storage ref"+ }+ },+ "nodeType": "Assignment",+ "operator": "=",+ "rightHandSide": {+ "argumentTypes": null,+ "id": 111,+ "name": "_bytes2VectorListVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 75,+ "src": "1004:20:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_array$_t_bytes2_$4_memory_$dyn_memory_ptr",+ "typeString": "bytes2[4] memory[] memory"+ }+ },+ "src": "982:42:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_array$_t_bytes2_$4_storage_$dyn_storage",+ "typeString": "bytes2[4] storage ref[] storage ref"+ }+ },+ "id": 113,+ "nodeType": "ExpressionStatement",+ "src": "982:42:0"+ },+ {+ "eventCall": {+ "argumentTypes": null,+ "arguments": [+ {+ "argumentTypes": null,+ "id": 115,+ "name": "_uintVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 53,+ "src": "1058:8:0",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ {+ "argumentTypes": null,+ "id": 116,+ "name": "_intVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 55,+ "src": "1068:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ }+ },+ {+ "argumentTypes": null,+ "id": 117,+ "name": "_boolVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 57,+ "src": "1077:8:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ }+ },+ {+ "argumentTypes": null,+ "id": 118,+ "name": "_int224Val",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 59,+ "src": "1087:10:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int224",+ "typeString": "int224"+ }+ },+ {+ "argumentTypes": null,+ "id": 119,+ "name": "_boolVectorVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 63,+ "src": "1099:14:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bool_$2_memory_ptr",+ "typeString": "bool[2] memory"+ }+ },+ {+ "argumentTypes": null,+ "id": 120,+ "name": "_intListVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 66,+ "src": "1115:11:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_int256_$dyn_memory_ptr",+ "typeString": "int256[] memory"+ }+ },+ {+ "argumentTypes": null,+ "id": 121,+ "name": "_stringVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 68,+ "src": "1128:10:0",+ "typeDescriptions": {+ "typeIdentifier": "t_string_memory_ptr",+ "typeString": "string memory"+ }+ },+ {+ "argumentTypes": null,+ "id": 122,+ "name": "_bytes16Val",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 70,+ "src": "1140:11:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes16",+ "typeString": "bytes16"+ }+ },+ {+ "argumentTypes": null,+ "id": 123,+ "name": "_bytes2VectorListVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 75,+ "src": "1153:20:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_array$_t_bytes2_$4_memory_$dyn_memory_ptr",+ "typeString": "bytes2[4] memory[] memory"+ }+ }+ ],+ "expression": {+ "argumentTypes": [+ {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ },+ {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ },+ {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ },+ {+ "typeIdentifier": "t_int224",+ "typeString": "int224"+ },+ {+ "typeIdentifier": "t_array$_t_bool_$2_memory_ptr",+ "typeString": "bool[2] memory"+ },+ {+ "typeIdentifier": "t_array$_t_int256_$dyn_memory_ptr",+ "typeString": "int256[] memory"+ },+ {+ "typeIdentifier": "t_string_memory_ptr",+ "typeString": "string memory"+ },+ {+ "typeIdentifier": "t_bytes16",+ "typeString": "bytes16"+ },+ {+ "typeIdentifier": "t_array$_t_array$_t_bytes2_$4_memory_$dyn_memory_ptr",+ "typeString": "bytes2[4] memory[] memory"+ }+ ],+ "id": 114,+ "name": "ValsSet",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 51,+ "src": "1050:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_function_event_nonpayable$_t_uint256_$_t_int256_$_t_bool_$_t_int224_$_t_array$_t_bool_$2_memory_ptr_$_t_array$_t_int256_$dyn_memory_ptr_$_t_string_memory_ptr_$_t_bytes16_$_t_array$_t_array$_t_bytes2_$4_memory_$dyn_memory_ptr_$returns$__$",+ "typeString": "function (uint256,int256,bool,int224,bool[2] memory,int256[] memory,string memory,bytes16,bytes2[4] memory[] memory)"+ }+ },+ "id": 124,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "functionCall",+ "lValueRequested": false,+ "names": [],+ "nodeType": "FunctionCall",+ "src": "1050:124:0",+ "typeDescriptions": {+ "typeIdentifier": "t_tuple$__$",+ "typeString": "tuple()"+ }+ },+ "id": 125,+ "nodeType": "EmitStatement",+ "src": "1045:129:0"+ }+ ]+ },+ "documentation": null,+ "id": 127,+ "implemented": true,+ "isConstructor": false,+ "isDeclaredConst": false,+ "modifiers": [],+ "name": "setValues",+ "nodeType": "FunctionDefinition",+ "parameters": {+ "id": 76,+ "nodeType": "ParameterList",+ "parameters": [+ {+ "constant": false,+ "id": 53,+ "name": "_uintVal",+ "nodeType": "VariableDeclaration",+ "scope": 127,+ "src": "458:13:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ },+ "typeName": {+ "id": 52,+ "name": "uint",+ "nodeType": "ElementaryTypeName",+ "src": "458:4:0",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 55,+ "name": "_intVal",+ "nodeType": "VariableDeclaration",+ "scope": 127,+ "src": "473:11:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ },+ "typeName": {+ "id": 54,+ "name": "int",+ "nodeType": "ElementaryTypeName",+ "src": "473:3:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 57,+ "name": "_boolVal",+ "nodeType": "VariableDeclaration",+ "scope": 127,+ "src": "486:13:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ },+ "typeName": {+ "id": 56,+ "name": "bool",+ "nodeType": "ElementaryTypeName",+ "src": "486:4:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 59,+ "name": "_int224Val",+ "nodeType": "VariableDeclaration",+ "scope": 127,+ "src": "501:17:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_int224",+ "typeString": "int224"+ },+ "typeName": {+ "id": 58,+ "name": "int224",+ "nodeType": "ElementaryTypeName",+ "src": "501:6:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int224",+ "typeString": "int224"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 63,+ "name": "_boolVectorVal",+ "nodeType": "VariableDeclaration",+ "scope": 127,+ "src": "520:22:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bool_$2_memory_ptr",+ "typeString": "bool[2]"+ },+ "typeName": {+ "baseType": {+ "id": 60,+ "name": "bool",+ "nodeType": "ElementaryTypeName",+ "src": "520:4:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ }+ },+ "id": 62,+ "length": {+ "argumentTypes": null,+ "hexValue": "32",+ "id": 61,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "number",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "525:1:0",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": null,+ "typeString": null+ },+ "value": "2"+ },+ "nodeType": "ArrayTypeName",+ "src": "520:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bool_$2_storage_ptr",+ "typeString": "bool[2]"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 66,+ "name": "_intListVal",+ "nodeType": "VariableDeclaration",+ "scope": 127,+ "src": "544:17:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_int256_$dyn_memory_ptr",+ "typeString": "int256[]"+ },+ "typeName": {+ "baseType": {+ "id": 64,+ "name": "int",+ "nodeType": "ElementaryTypeName",+ "src": "544:3:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ }+ },+ "id": 65,+ "length": null,+ "nodeType": "ArrayTypeName",+ "src": "544:5:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_int256_$dyn_storage_ptr",+ "typeString": "int256[]"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 68,+ "name": "_stringVal",+ "nodeType": "VariableDeclaration",+ "scope": 127,+ "src": "563:17:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_string_memory_ptr",+ "typeString": "string"+ },+ "typeName": {+ "id": 67,+ "name": "string",+ "nodeType": "ElementaryTypeName",+ "src": "563:6:0",+ "typeDescriptions": {+ "typeIdentifier": "t_string_storage_ptr",+ "typeString": "string"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 70,+ "name": "_bytes16Val",+ "nodeType": "VariableDeclaration",+ "scope": 127,+ "src": "582:19:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes16",+ "typeString": "bytes16"+ },+ "typeName": {+ "id": 69,+ "name": "bytes16",+ "nodeType": "ElementaryTypeName",+ "src": "582:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes16",+ "typeString": "bytes16"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 75,+ "name": "_bytes2VectorListVal",+ "nodeType": "VariableDeclaration",+ "scope": 127,+ "src": "603:32:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_array$_t_bytes2_$4_memory_$dyn_memory_ptr",+ "typeString": "bytes2[4][]"+ },+ "typeName": {+ "baseType": {+ "baseType": {+ "id": 71,+ "name": "bytes2",+ "nodeType": "ElementaryTypeName",+ "src": "603:6:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes2",+ "typeString": "bytes2"+ }+ },+ "id": 73,+ "length": {+ "argumentTypes": null,+ "hexValue": "34",+ "id": 72,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "number",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "610:1:0",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": null,+ "typeString": null+ },+ "value": "4"+ },+ "nodeType": "ArrayTypeName",+ "src": "603:9:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bytes2_$4_storage_ptr",+ "typeString": "bytes2[4]"+ }+ },+ "id": 74,+ "length": null,+ "nodeType": "ArrayTypeName",+ "src": "603:11:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_array$_t_bytes2_$4_storage_$dyn_storage_ptr",+ "typeString": "bytes2[4][]"+ }+ },+ "value": null,+ "visibility": "internal"+ }+ ],+ "src": "457:179:0"+ },+ "payable": false,+ "returnParameters": {+ "id": 77,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "644:0:0"+ },+ "scope": 167,+ "src": "439:742:0",+ "stateMutability": "nonpayable",+ "superFunction": null,+ "visibility": "public"+ },+ {+ "body": {+ "id": 165,+ "nodeType": "Block",+ "src": "1303:130:0",+ "statements": [+ {+ "expression": {+ "argumentTypes": null,+ "components": [+ {+ "argumentTypes": null,+ "id": 154,+ "name": "uintVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 3,+ "src": "1319:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ {+ "argumentTypes": null,+ "id": 155,+ "name": "intVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 5,+ "src": "1328:6:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ }+ },+ {+ "argumentTypes": null,+ "id": 156,+ "name": "boolVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 7,+ "src": "1336:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ }+ },+ {+ "argumentTypes": null,+ "id": 157,+ "name": "int224Val",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 9,+ "src": "1345:9:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int224",+ "typeString": "int224"+ }+ },+ {+ "argumentTypes": null,+ "id": 158,+ "name": "boolVectorVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 13,+ "src": "1356:13:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bool_$2_storage",+ "typeString": "bool[2] storage ref"+ }+ },+ {+ "argumentTypes": null,+ "id": 159,+ "name": "intListVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 16,+ "src": "1371:10:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_int256_$dyn_storage",+ "typeString": "int256[] storage ref"+ }+ },+ {+ "argumentTypes": null,+ "id": 160,+ "name": "stringVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 18,+ "src": "1383:9:0",+ "typeDescriptions": {+ "typeIdentifier": "t_string_storage",+ "typeString": "string storage ref"+ }+ },+ {+ "argumentTypes": null,+ "id": 161,+ "name": "bytes16Val",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 20,+ "src": "1394:10:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes16",+ "typeString": "bytes16"+ }+ },+ {+ "argumentTypes": null,+ "id": 162,+ "name": "bytes2VectorListVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 25,+ "src": "1406:19:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_array$_t_bytes2_$4_storage_$dyn_storage",+ "typeString": "bytes2[4] storage ref[] storage ref"+ }+ }+ ],+ "id": 163,+ "isConstant": false,+ "isInlineArray": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "nodeType": "TupleExpression",+ "src": "1318:108:0",+ "typeDescriptions": {+ "typeIdentifier": "t_tuple$_t_uint256_$_t_int256_$_t_bool_$_t_int224_$_t_array$_t_bool_$2_storage_$_t_array$_t_int256_$dyn_storage_$_t_string_storage_$_t_bytes16_$_t_array$_t_array$_t_bytes2_$4_storage_$dyn_storage_$",+ "typeString": "tuple(uint256,int256,bool,int224,bool[2] storage ref,int256[] storage ref,string storage ref,bytes16,bytes2[4] storage ref[] storage ref)"+ }+ },+ "functionReturnParameters": 153,+ "id": 164,+ "nodeType": "Return",+ "src": "1311:115:0"+ }+ ]+ },+ "documentation": null,+ "id": 166,+ "implemented": true,+ "isConstructor": false,+ "isDeclaredConst": true,+ "modifiers": [],+ "name": "getVals",+ "nodeType": "FunctionDefinition",+ "parameters": {+ "id": 128,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "1204:2:0"+ },+ "payable": false,+ "returnParameters": {+ "id": 153,+ "nodeType": "ParameterList",+ "parameters": [+ {+ "constant": false,+ "id": 130,+ "name": "",+ "nodeType": "VariableDeclaration",+ "scope": 166,+ "src": "1232:4:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ },+ "typeName": {+ "id": 129,+ "name": "uint",+ "nodeType": "ElementaryTypeName",+ "src": "1232:4:0",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 132,+ "name": "",+ "nodeType": "VariableDeclaration",+ "scope": 166,+ "src": "1238:3:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ },+ "typeName": {+ "id": 131,+ "name": "int",+ "nodeType": "ElementaryTypeName",+ "src": "1238:3:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 134,+ "name": "",+ "nodeType": "VariableDeclaration",+ "scope": 166,+ "src": "1243:4:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ },+ "typeName": {+ "id": 133,+ "name": "bool",+ "nodeType": "ElementaryTypeName",+ "src": "1243:4:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 136,+ "name": "",+ "nodeType": "VariableDeclaration",+ "scope": 166,+ "src": "1249:6:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_int224",+ "typeString": "int224"+ },+ "typeName": {+ "id": 135,+ "name": "int224",+ "nodeType": "ElementaryTypeName",+ "src": "1249:6:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int224",+ "typeString": "int224"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 140,+ "name": "",+ "nodeType": "VariableDeclaration",+ "scope": 166,+ "src": "1257:7:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bool_$2_memory_ptr",+ "typeString": "bool[2]"+ },+ "typeName": {+ "baseType": {+ "id": 137,+ "name": "bool",+ "nodeType": "ElementaryTypeName",+ "src": "1257:4:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ }+ },+ "id": 139,+ "length": {+ "argumentTypes": null,+ "hexValue": "32",+ "id": 138,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "number",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "1262:1:0",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": null,+ "typeString": null+ },+ "value": "2"+ },+ "nodeType": "ArrayTypeName",+ "src": "1257:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bool_$2_storage_ptr",+ "typeString": "bool[2]"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 143,+ "name": "",+ "nodeType": "VariableDeclaration",+ "scope": 166,+ "src": "1266:5:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_int256_$dyn_memory_ptr",+ "typeString": "int256[]"+ },+ "typeName": {+ "baseType": {+ "id": 141,+ "name": "int",+ "nodeType": "ElementaryTypeName",+ "src": "1266:3:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ }+ },+ "id": 142,+ "length": null,+ "nodeType": "ArrayTypeName",+ "src": "1266:5:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_int256_$dyn_storage_ptr",+ "typeString": "int256[]"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 145,+ "name": "",+ "nodeType": "VariableDeclaration",+ "scope": 166,+ "src": "1273:6:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_string_memory_ptr",+ "typeString": "string"+ },+ "typeName": {+ "id": 144,+ "name": "string",+ "nodeType": "ElementaryTypeName",+ "src": "1273:6:0",+ "typeDescriptions": {+ "typeIdentifier": "t_string_storage_ptr",+ "typeString": "string"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 147,+ "name": "",+ "nodeType": "VariableDeclaration",+ "scope": 166,+ "src": "1281:7:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes16",+ "typeString": "bytes16"+ },+ "typeName": {+ "id": 146,+ "name": "bytes16",+ "nodeType": "ElementaryTypeName",+ "src": "1281:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes16",+ "typeString": "bytes16"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 152,+ "name": "",+ "nodeType": "VariableDeclaration",+ "scope": 166,+ "src": "1290:11:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_array$_t_bytes2_$4_memory_$dyn_memory_ptr",+ "typeString": "bytes2[4][]"+ },+ "typeName": {+ "baseType": {+ "baseType": {+ "id": 148,+ "name": "bytes2",+ "nodeType": "ElementaryTypeName",+ "src": "1290:6:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes2",+ "typeString": "bytes2"+ }+ },+ "id": 150,+ "length": {+ "argumentTypes": null,+ "hexValue": "34",+ "id": 149,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "number",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "1297:1:0",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": null,+ "typeString": null+ },+ "value": "4"+ },+ "nodeType": "ArrayTypeName",+ "src": "1290:9:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bytes2_$4_storage_ptr",+ "typeString": "bytes2[4]"+ }+ },+ "id": 151,+ "length": null,+ "nodeType": "ArrayTypeName",+ "src": "1290:11:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_array$_t_bytes2_$4_storage_$dyn_storage_ptr",+ "typeString": "bytes2[4][]"+ }+ },+ "value": null,+ "visibility": "internal"+ }+ ],+ "src": "1231:71:0"+ },+ "scope": 167,+ "src": "1187:246:0",+ "stateMutability": "view",+ "superFunction": null,+ "visibility": "public"+ }+ ],+ "scope": 168,+ "src": "26:1413:0"+ }+ ],+ "src": "0:1440:0"+ },+ "legacyAST": {+ "absolutePath": "/home/akru/hsweb3test/contracts/ComplexStorage.sol",+ "exportedSymbols": {+ "ComplexStorage": [+ 167+ ]+ },+ "id": 168,+ "nodeType": "SourceUnit",+ "nodes": [+ {+ "id": 1,+ "literals": [+ "solidity",+ "^",+ "0.4",+ ".13"+ ],+ "nodeType": "PragmaDirective",+ "src": "0:24:0"+ },+ {+ "baseContracts": [],+ "contractDependencies": [],+ "contractKind": "contract",+ "documentation": null,+ "fullyImplemented": true,+ "id": 167,+ "linearizedBaseContracts": [+ 167+ ],+ "name": "ComplexStorage",+ "nodeType": "ContractDefinition",+ "nodes": [+ {+ "constant": false,+ "id": 3,+ "name": "uintVal",+ "nodeType": "VariableDeclaration",+ "scope": 167,+ "src": "56:19:0",+ "stateVariable": true,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ },+ "typeName": {+ "id": 2,+ "name": "uint",+ "nodeType": "ElementaryTypeName",+ "src": "56:4:0",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "value": null,+ "visibility": "public"+ },+ {+ "constant": false,+ "id": 5,+ "name": "intVal",+ "nodeType": "VariableDeclaration",+ "scope": 167,+ "src": "81:17:0",+ "stateVariable": true,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ },+ "typeName": {+ "id": 4,+ "name": "int",+ "nodeType": "ElementaryTypeName",+ "src": "81:3:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ }+ },+ "value": null,+ "visibility": "public"+ },+ {+ "constant": false,+ "id": 7,+ "name": "boolVal",+ "nodeType": "VariableDeclaration",+ "scope": 167,+ "src": "104:19:0",+ "stateVariable": true,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ },+ "typeName": {+ "id": 6,+ "name": "bool",+ "nodeType": "ElementaryTypeName",+ "src": "104:4:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ }+ },+ "value": null,+ "visibility": "public"+ },+ {+ "constant": false,+ "id": 9,+ "name": "int224Val",+ "nodeType": "VariableDeclaration",+ "scope": 167,+ "src": "129:23:0",+ "stateVariable": true,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_int224",+ "typeString": "int224"+ },+ "typeName": {+ "id": 8,+ "name": "int224",+ "nodeType": "ElementaryTypeName",+ "src": "129:6:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int224",+ "typeString": "int224"+ }+ },+ "value": null,+ "visibility": "public"+ },+ {+ "constant": false,+ "id": 13,+ "name": "boolVectorVal",+ "nodeType": "VariableDeclaration",+ "scope": 167,+ "src": "158:28:0",+ "stateVariable": true,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bool_$2_storage",+ "typeString": "bool[2]"+ },+ "typeName": {+ "baseType": {+ "id": 10,+ "name": "bool",+ "nodeType": "ElementaryTypeName",+ "src": "158:4:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ }+ },+ "id": 12,+ "length": {+ "argumentTypes": null,+ "hexValue": "32",+ "id": 11,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "number",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "163:1:0",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": null,+ "typeString": null+ },+ "value": "2"+ },+ "nodeType": "ArrayTypeName",+ "src": "158:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bool_$2_storage_ptr",+ "typeString": "bool[2]"+ }+ },+ "value": null,+ "visibility": "public"+ },+ {+ "constant": false,+ "id": 16,+ "name": "intListVal",+ "nodeType": "VariableDeclaration",+ "scope": 167,+ "src": "192:23:0",+ "stateVariable": true,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_int256_$dyn_storage",+ "typeString": "int256[]"+ },+ "typeName": {+ "baseType": {+ "id": 14,+ "name": "int",+ "nodeType": "ElementaryTypeName",+ "src": "192:3:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ }+ },+ "id": 15,+ "length": null,+ "nodeType": "ArrayTypeName",+ "src": "192:5:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_int256_$dyn_storage_ptr",+ "typeString": "int256[]"+ }+ },+ "value": null,+ "visibility": "public"+ },+ {+ "constant": false,+ "id": 18,+ "name": "stringVal",+ "nodeType": "VariableDeclaration",+ "scope": 167,+ "src": "221:23:0",+ "stateVariable": true,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_string_storage",+ "typeString": "string"+ },+ "typeName": {+ "id": 17,+ "name": "string",+ "nodeType": "ElementaryTypeName",+ "src": "221:6:0",+ "typeDescriptions": {+ "typeIdentifier": "t_string_storage_ptr",+ "typeString": "string"+ }+ },+ "value": null,+ "visibility": "public"+ },+ {+ "constant": false,+ "id": 20,+ "name": "bytes16Val",+ "nodeType": "VariableDeclaration",+ "scope": 167,+ "src": "250:25:0",+ "stateVariable": true,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes16",+ "typeString": "bytes16"+ },+ "typeName": {+ "id": 19,+ "name": "bytes16",+ "nodeType": "ElementaryTypeName",+ "src": "250:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes16",+ "typeString": "bytes16"+ }+ },+ "value": null,+ "visibility": "public"+ },+ {+ "constant": false,+ "id": 25,+ "name": "bytes2VectorListVal",+ "nodeType": "VariableDeclaration",+ "scope": 167,+ "src": "281:38:0",+ "stateVariable": true,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_array$_t_bytes2_$4_storage_$dyn_storage",+ "typeString": "bytes2[4][]"+ },+ "typeName": {+ "baseType": {+ "baseType": {+ "id": 21,+ "name": "bytes2",+ "nodeType": "ElementaryTypeName",+ "src": "281:6:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes2",+ "typeString": "bytes2"+ }+ },+ "id": 23,+ "length": {+ "argumentTypes": null,+ "hexValue": "34",+ "id": 22,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "number",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "288:1:0",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": null,+ "typeString": null+ },+ "value": "4"+ },+ "nodeType": "ArrayTypeName",+ "src": "281:9:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bytes2_$4_storage_ptr",+ "typeString": "bytes2[4]"+ }+ },+ "id": 24,+ "length": null,+ "nodeType": "ArrayTypeName",+ "src": "281:11:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_array$_t_bytes2_$4_storage_$dyn_storage_ptr",+ "typeString": "bytes2[4][]"+ }+ },+ "value": null,+ "visibility": "public"+ },+ {+ "anonymous": false,+ "documentation": null,+ "id": 51,+ "name": "ValsSet",+ "nodeType": "EventDefinition",+ "parameters": {+ "id": 50,+ "nodeType": "ParameterList",+ "parameters": [+ {+ "constant": false,+ "id": 27,+ "indexed": false,+ "name": "a",+ "nodeType": "VariableDeclaration",+ "scope": 51,+ "src": "340:6:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ },+ "typeName": {+ "id": 26,+ "name": "uint",+ "nodeType": "ElementaryTypeName",+ "src": "340:4:0",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 29,+ "indexed": false,+ "name": "b",+ "nodeType": "VariableDeclaration",+ "scope": 51,+ "src": "348:5:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ },+ "typeName": {+ "id": 28,+ "name": "int",+ "nodeType": "ElementaryTypeName",+ "src": "348:3:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 31,+ "indexed": false,+ "name": "c",+ "nodeType": "VariableDeclaration",+ "scope": 51,+ "src": "355:6:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ },+ "typeName": {+ "id": 30,+ "name": "bool",+ "nodeType": "ElementaryTypeName",+ "src": "355:4:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 33,+ "indexed": false,+ "name": "d",+ "nodeType": "VariableDeclaration",+ "scope": 51,+ "src": "363:8:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_int224",+ "typeString": "int224"+ },+ "typeName": {+ "id": 32,+ "name": "int224",+ "nodeType": "ElementaryTypeName",+ "src": "363:6:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int224",+ "typeString": "int224"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 37,+ "indexed": false,+ "name": "e",+ "nodeType": "VariableDeclaration",+ "scope": 51,+ "src": "373:9:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bool_$2_memory_ptr",+ "typeString": "bool[2]"+ },+ "typeName": {+ "baseType": {+ "id": 34,+ "name": "bool",+ "nodeType": "ElementaryTypeName",+ "src": "373:4:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ }+ },+ "id": 36,+ "length": {+ "argumentTypes": null,+ "hexValue": "32",+ "id": 35,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "number",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "378:1:0",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": null,+ "typeString": null+ },+ "value": "2"+ },+ "nodeType": "ArrayTypeName",+ "src": "373:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bool_$2_storage_ptr",+ "typeString": "bool[2]"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 40,+ "indexed": false,+ "name": "f",+ "nodeType": "VariableDeclaration",+ "scope": 51,+ "src": "384:7:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_int256_$dyn_memory_ptr",+ "typeString": "int256[]"+ },+ "typeName": {+ "baseType": {+ "id": 38,+ "name": "int",+ "nodeType": "ElementaryTypeName",+ "src": "384:3:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ }+ },+ "id": 39,+ "length": null,+ "nodeType": "ArrayTypeName",+ "src": "384:5:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_int256_$dyn_storage_ptr",+ "typeString": "int256[]"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 42,+ "indexed": false,+ "name": "g",+ "nodeType": "VariableDeclaration",+ "scope": 51,+ "src": "393:8:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_string_memory_ptr",+ "typeString": "string"+ },+ "typeName": {+ "id": 41,+ "name": "string",+ "nodeType": "ElementaryTypeName",+ "src": "393:6:0",+ "typeDescriptions": {+ "typeIdentifier": "t_string_storage_ptr",+ "typeString": "string"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 44,+ "indexed": false,+ "name": "h",+ "nodeType": "VariableDeclaration",+ "scope": 51,+ "src": "403:9:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes16",+ "typeString": "bytes16"+ },+ "typeName": {+ "id": 43,+ "name": "bytes16",+ "nodeType": "ElementaryTypeName",+ "src": "403:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes16",+ "typeString": "bytes16"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 49,+ "indexed": false,+ "name": "i",+ "nodeType": "VariableDeclaration",+ "scope": 51,+ "src": "414:13:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_array$_t_bytes2_$4_memory_$dyn_memory_ptr",+ "typeString": "bytes2[4][]"+ },+ "typeName": {+ "baseType": {+ "baseType": {+ "id": 45,+ "name": "bytes2",+ "nodeType": "ElementaryTypeName",+ "src": "414:6:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes2",+ "typeString": "bytes2"+ }+ },+ "id": 47,+ "length": {+ "argumentTypes": null,+ "hexValue": "34",+ "id": 46,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "number",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "421:1:0",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": null,+ "typeString": null+ },+ "value": "4"+ },+ "nodeType": "ArrayTypeName",+ "src": "414:9:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bytes2_$4_storage_ptr",+ "typeString": "bytes2[4]"+ }+ },+ "id": 48,+ "length": null,+ "nodeType": "ArrayTypeName",+ "src": "414:11:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_array$_t_bytes2_$4_storage_$dyn_storage_ptr",+ "typeString": "bytes2[4][]"+ }+ },+ "value": null,+ "visibility": "internal"+ }+ ],+ "src": "339:89:0"+ },+ "src": "326:103:0"+ },+ {+ "body": {+ "id": 126,+ "nodeType": "Block",+ "src": "644:537:0",+ "statements": [+ {+ "expression": {+ "argumentTypes": null,+ "id": 80,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "leftHandSide": {+ "argumentTypes": null,+ "id": 78,+ "name": "uintVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 3,+ "src": "655:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "nodeType": "Assignment",+ "operator": "=",+ "rightHandSide": {+ "argumentTypes": null,+ "id": 79,+ "name": "_uintVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 53,+ "src": "675:8:0",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "src": "655:28:0",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "id": 81,+ "nodeType": "ExpressionStatement",+ "src": "655:28:0"+ },+ {+ "expression": {+ "argumentTypes": null,+ "id": 84,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "leftHandSide": {+ "argumentTypes": null,+ "id": 82,+ "name": "intVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 5,+ "src": "694:6:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ }+ },+ "nodeType": "Assignment",+ "operator": "=",+ "rightHandSide": {+ "argumentTypes": null,+ "id": 83,+ "name": "_intVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 55,+ "src": "714:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ }+ },+ "src": "694:27:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ }+ },+ "id": 85,+ "nodeType": "ExpressionStatement",+ "src": "694:27:0"+ },+ {+ "expression": {+ "argumentTypes": null,+ "id": 88,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "leftHandSide": {+ "argumentTypes": null,+ "id": 86,+ "name": "boolVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 7,+ "src": "732:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ }+ },+ "nodeType": "Assignment",+ "operator": "=",+ "rightHandSide": {+ "argumentTypes": null,+ "id": 87,+ "name": "_boolVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 57,+ "src": "752:8:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ }+ },+ "src": "732:28:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ }+ },+ "id": 89,+ "nodeType": "ExpressionStatement",+ "src": "732:28:0"+ },+ {+ "expression": {+ "argumentTypes": null,+ "id": 92,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "leftHandSide": {+ "argumentTypes": null,+ "id": 90,+ "name": "int224Val",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 9,+ "src": "771:9:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int224",+ "typeString": "int224"+ }+ },+ "nodeType": "Assignment",+ "operator": "=",+ "rightHandSide": {+ "argumentTypes": null,+ "id": 91,+ "name": "_int224Val",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 59,+ "src": "791:10:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int224",+ "typeString": "int224"+ }+ },+ "src": "771:30:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int224",+ "typeString": "int224"+ }+ },+ "id": 93,+ "nodeType": "ExpressionStatement",+ "src": "771:30:0"+ },+ {+ "expression": {+ "argumentTypes": null,+ "id": 96,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "leftHandSide": {+ "argumentTypes": null,+ "id": 94,+ "name": "boolVectorVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 13,+ "src": "812:13:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bool_$2_storage",+ "typeString": "bool[2] storage ref"+ }+ },+ "nodeType": "Assignment",+ "operator": "=",+ "rightHandSide": {+ "argumentTypes": null,+ "id": 95,+ "name": "_boolVectorVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 63,+ "src": "832:14:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bool_$2_memory_ptr",+ "typeString": "bool[2] memory"+ }+ },+ "src": "812:34:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bool_$2_storage",+ "typeString": "bool[2] storage ref"+ }+ },+ "id": 97,+ "nodeType": "ExpressionStatement",+ "src": "812:34:0"+ },+ {+ "expression": {+ "argumentTypes": null,+ "id": 100,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "leftHandSide": {+ "argumentTypes": null,+ "id": 98,+ "name": "intListVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 16,+ "src": "857:10:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_int256_$dyn_storage",+ "typeString": "int256[] storage ref"+ }+ },+ "nodeType": "Assignment",+ "operator": "=",+ "rightHandSide": {+ "argumentTypes": null,+ "id": 99,+ "name": "_intListVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 66,+ "src": "877:11:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_int256_$dyn_memory_ptr",+ "typeString": "int256[] memory"+ }+ },+ "src": "857:31:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_int256_$dyn_storage",+ "typeString": "int256[] storage ref"+ }+ },+ "id": 101,+ "nodeType": "ExpressionStatement",+ "src": "857:31:0"+ },+ {+ "expression": {+ "argumentTypes": null,+ "id": 104,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "leftHandSide": {+ "argumentTypes": null,+ "id": 102,+ "name": "stringVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 18,+ "src": "899:9:0",+ "typeDescriptions": {+ "typeIdentifier": "t_string_storage",+ "typeString": "string storage ref"+ }+ },+ "nodeType": "Assignment",+ "operator": "=",+ "rightHandSide": {+ "argumentTypes": null,+ "id": 103,+ "name": "_stringVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 68,+ "src": "919:10:0",+ "typeDescriptions": {+ "typeIdentifier": "t_string_memory_ptr",+ "typeString": "string memory"+ }+ },+ "src": "899:30:0",+ "typeDescriptions": {+ "typeIdentifier": "t_string_storage",+ "typeString": "string storage ref"+ }+ },+ "id": 105,+ "nodeType": "ExpressionStatement",+ "src": "899:30:0"+ },+ {+ "expression": {+ "argumentTypes": null,+ "id": 108,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "leftHandSide": {+ "argumentTypes": null,+ "id": 106,+ "name": "bytes16Val",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 20,+ "src": "940:10:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes16",+ "typeString": "bytes16"+ }+ },+ "nodeType": "Assignment",+ "operator": "=",+ "rightHandSide": {+ "argumentTypes": null,+ "id": 107,+ "name": "_bytes16Val",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 70,+ "src": "960:11:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes16",+ "typeString": "bytes16"+ }+ },+ "src": "940:31:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes16",+ "typeString": "bytes16"+ }+ },+ "id": 109,+ "nodeType": "ExpressionStatement",+ "src": "940:31:0"+ },+ {+ "expression": {+ "argumentTypes": null,+ "id": 112,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "leftHandSide": {+ "argumentTypes": null,+ "id": 110,+ "name": "bytes2VectorListVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 25,+ "src": "982:19:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_array$_t_bytes2_$4_storage_$dyn_storage",+ "typeString": "bytes2[4] storage ref[] storage ref"+ }+ },+ "nodeType": "Assignment",+ "operator": "=",+ "rightHandSide": {+ "argumentTypes": null,+ "id": 111,+ "name": "_bytes2VectorListVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 75,+ "src": "1004:20:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_array$_t_bytes2_$4_memory_$dyn_memory_ptr",+ "typeString": "bytes2[4] memory[] memory"+ }+ },+ "src": "982:42:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_array$_t_bytes2_$4_storage_$dyn_storage",+ "typeString": "bytes2[4] storage ref[] storage ref"+ }+ },+ "id": 113,+ "nodeType": "ExpressionStatement",+ "src": "982:42:0"+ },+ {+ "eventCall": {+ "argumentTypes": null,+ "arguments": [+ {+ "argumentTypes": null,+ "id": 115,+ "name": "_uintVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 53,+ "src": "1058:8:0",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ {+ "argumentTypes": null,+ "id": 116,+ "name": "_intVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 55,+ "src": "1068:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ }+ },+ {+ "argumentTypes": null,+ "id": 117,+ "name": "_boolVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 57,+ "src": "1077:8:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ }+ },+ {+ "argumentTypes": null,+ "id": 118,+ "name": "_int224Val",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 59,+ "src": "1087:10:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int224",+ "typeString": "int224"+ }+ },+ {+ "argumentTypes": null,+ "id": 119,+ "name": "_boolVectorVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 63,+ "src": "1099:14:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bool_$2_memory_ptr",+ "typeString": "bool[2] memory"+ }+ },+ {+ "argumentTypes": null,+ "id": 120,+ "name": "_intListVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 66,+ "src": "1115:11:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_int256_$dyn_memory_ptr",+ "typeString": "int256[] memory"+ }+ },+ {+ "argumentTypes": null,+ "id": 121,+ "name": "_stringVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 68,+ "src": "1128:10:0",+ "typeDescriptions": {+ "typeIdentifier": "t_string_memory_ptr",+ "typeString": "string memory"+ }+ },+ {+ "argumentTypes": null,+ "id": 122,+ "name": "_bytes16Val",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 70,+ "src": "1140:11:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes16",+ "typeString": "bytes16"+ }+ },+ {+ "argumentTypes": null,+ "id": 123,+ "name": "_bytes2VectorListVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 75,+ "src": "1153:20:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_array$_t_bytes2_$4_memory_$dyn_memory_ptr",+ "typeString": "bytes2[4] memory[] memory"+ }+ }+ ],+ "expression": {+ "argumentTypes": [+ {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ },+ {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ },+ {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ },+ {+ "typeIdentifier": "t_int224",+ "typeString": "int224"+ },+ {+ "typeIdentifier": "t_array$_t_bool_$2_memory_ptr",+ "typeString": "bool[2] memory"+ },+ {+ "typeIdentifier": "t_array$_t_int256_$dyn_memory_ptr",+ "typeString": "int256[] memory"+ },+ {+ "typeIdentifier": "t_string_memory_ptr",+ "typeString": "string memory"+ },+ {+ "typeIdentifier": "t_bytes16",+ "typeString": "bytes16"+ },+ {+ "typeIdentifier": "t_array$_t_array$_t_bytes2_$4_memory_$dyn_memory_ptr",+ "typeString": "bytes2[4] memory[] memory"+ }+ ],+ "id": 114,+ "name": "ValsSet",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 51,+ "src": "1050:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_function_event_nonpayable$_t_uint256_$_t_int256_$_t_bool_$_t_int224_$_t_array$_t_bool_$2_memory_ptr_$_t_array$_t_int256_$dyn_memory_ptr_$_t_string_memory_ptr_$_t_bytes16_$_t_array$_t_array$_t_bytes2_$4_memory_$dyn_memory_ptr_$returns$__$",+ "typeString": "function (uint256,int256,bool,int224,bool[2] memory,int256[] memory,string memory,bytes16,bytes2[4] memory[] memory)"+ }+ },+ "id": 124,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "functionCall",+ "lValueRequested": false,+ "names": [],+ "nodeType": "FunctionCall",+ "src": "1050:124:0",+ "typeDescriptions": {+ "typeIdentifier": "t_tuple$__$",+ "typeString": "tuple()"+ }+ },+ "id": 125,+ "nodeType": "EmitStatement",+ "src": "1045:129:0"+ }+ ]+ },+ "documentation": null,+ "id": 127,+ "implemented": true,+ "isConstructor": false,+ "isDeclaredConst": false,+ "modifiers": [],+ "name": "setValues",+ "nodeType": "FunctionDefinition",+ "parameters": {+ "id": 76,+ "nodeType": "ParameterList",+ "parameters": [+ {+ "constant": false,+ "id": 53,+ "name": "_uintVal",+ "nodeType": "VariableDeclaration",+ "scope": 127,+ "src": "458:13:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ },+ "typeName": {+ "id": 52,+ "name": "uint",+ "nodeType": "ElementaryTypeName",+ "src": "458:4:0",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 55,+ "name": "_intVal",+ "nodeType": "VariableDeclaration",+ "scope": 127,+ "src": "473:11:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ },+ "typeName": {+ "id": 54,+ "name": "int",+ "nodeType": "ElementaryTypeName",+ "src": "473:3:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 57,+ "name": "_boolVal",+ "nodeType": "VariableDeclaration",+ "scope": 127,+ "src": "486:13:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ },+ "typeName": {+ "id": 56,+ "name": "bool",+ "nodeType": "ElementaryTypeName",+ "src": "486:4:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 59,+ "name": "_int224Val",+ "nodeType": "VariableDeclaration",+ "scope": 127,+ "src": "501:17:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_int224",+ "typeString": "int224"+ },+ "typeName": {+ "id": 58,+ "name": "int224",+ "nodeType": "ElementaryTypeName",+ "src": "501:6:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int224",+ "typeString": "int224"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 63,+ "name": "_boolVectorVal",+ "nodeType": "VariableDeclaration",+ "scope": 127,+ "src": "520:22:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bool_$2_memory_ptr",+ "typeString": "bool[2]"+ },+ "typeName": {+ "baseType": {+ "id": 60,+ "name": "bool",+ "nodeType": "ElementaryTypeName",+ "src": "520:4:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ }+ },+ "id": 62,+ "length": {+ "argumentTypes": null,+ "hexValue": "32",+ "id": 61,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "number",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "525:1:0",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": null,+ "typeString": null+ },+ "value": "2"+ },+ "nodeType": "ArrayTypeName",+ "src": "520:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bool_$2_storage_ptr",+ "typeString": "bool[2]"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 66,+ "name": "_intListVal",+ "nodeType": "VariableDeclaration",+ "scope": 127,+ "src": "544:17:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_int256_$dyn_memory_ptr",+ "typeString": "int256[]"+ },+ "typeName": {+ "baseType": {+ "id": 64,+ "name": "int",+ "nodeType": "ElementaryTypeName",+ "src": "544:3:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ }+ },+ "id": 65,+ "length": null,+ "nodeType": "ArrayTypeName",+ "src": "544:5:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_int256_$dyn_storage_ptr",+ "typeString": "int256[]"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 68,+ "name": "_stringVal",+ "nodeType": "VariableDeclaration",+ "scope": 127,+ "src": "563:17:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_string_memory_ptr",+ "typeString": "string"+ },+ "typeName": {+ "id": 67,+ "name": "string",+ "nodeType": "ElementaryTypeName",+ "src": "563:6:0",+ "typeDescriptions": {+ "typeIdentifier": "t_string_storage_ptr",+ "typeString": "string"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 70,+ "name": "_bytes16Val",+ "nodeType": "VariableDeclaration",+ "scope": 127,+ "src": "582:19:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes16",+ "typeString": "bytes16"+ },+ "typeName": {+ "id": 69,+ "name": "bytes16",+ "nodeType": "ElementaryTypeName",+ "src": "582:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes16",+ "typeString": "bytes16"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 75,+ "name": "_bytes2VectorListVal",+ "nodeType": "VariableDeclaration",+ "scope": 127,+ "src": "603:32:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_array$_t_bytes2_$4_memory_$dyn_memory_ptr",+ "typeString": "bytes2[4][]"+ },+ "typeName": {+ "baseType": {+ "baseType": {+ "id": 71,+ "name": "bytes2",+ "nodeType": "ElementaryTypeName",+ "src": "603:6:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes2",+ "typeString": "bytes2"+ }+ },+ "id": 73,+ "length": {+ "argumentTypes": null,+ "hexValue": "34",+ "id": 72,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "number",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "610:1:0",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": null,+ "typeString": null+ },+ "value": "4"+ },+ "nodeType": "ArrayTypeName",+ "src": "603:9:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bytes2_$4_storage_ptr",+ "typeString": "bytes2[4]"+ }+ },+ "id": 74,+ "length": null,+ "nodeType": "ArrayTypeName",+ "src": "603:11:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_array$_t_bytes2_$4_storage_$dyn_storage_ptr",+ "typeString": "bytes2[4][]"+ }+ },+ "value": null,+ "visibility": "internal"+ }+ ],+ "src": "457:179:0"+ },+ "payable": false,+ "returnParameters": {+ "id": 77,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "644:0:0"+ },+ "scope": 167,+ "src": "439:742:0",+ "stateMutability": "nonpayable",+ "superFunction": null,+ "visibility": "public"+ },+ {+ "body": {+ "id": 165,+ "nodeType": "Block",+ "src": "1303:130:0",+ "statements": [+ {+ "expression": {+ "argumentTypes": null,+ "components": [+ {+ "argumentTypes": null,+ "id": 154,+ "name": "uintVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 3,+ "src": "1319:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ {+ "argumentTypes": null,+ "id": 155,+ "name": "intVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 5,+ "src": "1328:6:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ }+ },+ {+ "argumentTypes": null,+ "id": 156,+ "name": "boolVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 7,+ "src": "1336:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ }+ },+ {+ "argumentTypes": null,+ "id": 157,+ "name": "int224Val",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 9,+ "src": "1345:9:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int224",+ "typeString": "int224"+ }+ },+ {+ "argumentTypes": null,+ "id": 158,+ "name": "boolVectorVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 13,+ "src": "1356:13:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bool_$2_storage",+ "typeString": "bool[2] storage ref"+ }+ },+ {+ "argumentTypes": null,+ "id": 159,+ "name": "intListVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 16,+ "src": "1371:10:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_int256_$dyn_storage",+ "typeString": "int256[] storage ref"+ }+ },+ {+ "argumentTypes": null,+ "id": 160,+ "name": "stringVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 18,+ "src": "1383:9:0",+ "typeDescriptions": {+ "typeIdentifier": "t_string_storage",+ "typeString": "string storage ref"+ }+ },+ {+ "argumentTypes": null,+ "id": 161,+ "name": "bytes16Val",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 20,+ "src": "1394:10:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes16",+ "typeString": "bytes16"+ }+ },+ {+ "argumentTypes": null,+ "id": 162,+ "name": "bytes2VectorListVal",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 25,+ "src": "1406:19:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_array$_t_bytes2_$4_storage_$dyn_storage",+ "typeString": "bytes2[4] storage ref[] storage ref"+ }+ }+ ],+ "id": 163,+ "isConstant": false,+ "isInlineArray": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "nodeType": "TupleExpression",+ "src": "1318:108:0",+ "typeDescriptions": {+ "typeIdentifier": "t_tuple$_t_uint256_$_t_int256_$_t_bool_$_t_int224_$_t_array$_t_bool_$2_storage_$_t_array$_t_int256_$dyn_storage_$_t_string_storage_$_t_bytes16_$_t_array$_t_array$_t_bytes2_$4_storage_$dyn_storage_$",+ "typeString": "tuple(uint256,int256,bool,int224,bool[2] storage ref,int256[] storage ref,string storage ref,bytes16,bytes2[4] storage ref[] storage ref)"+ }+ },+ "functionReturnParameters": 153,+ "id": 164,+ "nodeType": "Return",+ "src": "1311:115:0"+ }+ ]+ },+ "documentation": null,+ "id": 166,+ "implemented": true,+ "isConstructor": false,+ "isDeclaredConst": true,+ "modifiers": [],+ "name": "getVals",+ "nodeType": "FunctionDefinition",+ "parameters": {+ "id": 128,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "1204:2:0"+ },+ "payable": false,+ "returnParameters": {+ "id": 153,+ "nodeType": "ParameterList",+ "parameters": [+ {+ "constant": false,+ "id": 130,+ "name": "",+ "nodeType": "VariableDeclaration",+ "scope": 166,+ "src": "1232:4:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ },+ "typeName": {+ "id": 129,+ "name": "uint",+ "nodeType": "ElementaryTypeName",+ "src": "1232:4:0",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 132,+ "name": "",+ "nodeType": "VariableDeclaration",+ "scope": 166,+ "src": "1238:3:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ },+ "typeName": {+ "id": 131,+ "name": "int",+ "nodeType": "ElementaryTypeName",+ "src": "1238:3:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 134,+ "name": "",+ "nodeType": "VariableDeclaration",+ "scope": 166,+ "src": "1243:4:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ },+ "typeName": {+ "id": 133,+ "name": "bool",+ "nodeType": "ElementaryTypeName",+ "src": "1243:4:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 136,+ "name": "",+ "nodeType": "VariableDeclaration",+ "scope": 166,+ "src": "1249:6:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_int224",+ "typeString": "int224"+ },+ "typeName": {+ "id": 135,+ "name": "int224",+ "nodeType": "ElementaryTypeName",+ "src": "1249:6:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int224",+ "typeString": "int224"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 140,+ "name": "",+ "nodeType": "VariableDeclaration",+ "scope": 166,+ "src": "1257:7:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bool_$2_memory_ptr",+ "typeString": "bool[2]"+ },+ "typeName": {+ "baseType": {+ "id": 137,+ "name": "bool",+ "nodeType": "ElementaryTypeName",+ "src": "1257:4:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bool",+ "typeString": "bool"+ }+ },+ "id": 139,+ "length": {+ "argumentTypes": null,+ "hexValue": "32",+ "id": 138,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "number",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "1262:1:0",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": null,+ "typeString": null+ },+ "value": "2"+ },+ "nodeType": "ArrayTypeName",+ "src": "1257:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bool_$2_storage_ptr",+ "typeString": "bool[2]"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 143,+ "name": "",+ "nodeType": "VariableDeclaration",+ "scope": 166,+ "src": "1266:5:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_int256_$dyn_memory_ptr",+ "typeString": "int256[]"+ },+ "typeName": {+ "baseType": {+ "id": 141,+ "name": "int",+ "nodeType": "ElementaryTypeName",+ "src": "1266:3:0",+ "typeDescriptions": {+ "typeIdentifier": "t_int256",+ "typeString": "int256"+ }+ },+ "id": 142,+ "length": null,+ "nodeType": "ArrayTypeName",+ "src": "1266:5:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_int256_$dyn_storage_ptr",+ "typeString": "int256[]"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 145,+ "name": "",+ "nodeType": "VariableDeclaration",+ "scope": 166,+ "src": "1273:6:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_string_memory_ptr",+ "typeString": "string"+ },+ "typeName": {+ "id": 144,+ "name": "string",+ "nodeType": "ElementaryTypeName",+ "src": "1273:6:0",+ "typeDescriptions": {+ "typeIdentifier": "t_string_storage_ptr",+ "typeString": "string"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 147,+ "name": "",+ "nodeType": "VariableDeclaration",+ "scope": 166,+ "src": "1281:7:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes16",+ "typeString": "bytes16"+ },+ "typeName": {+ "id": 146,+ "name": "bytes16",+ "nodeType": "ElementaryTypeName",+ "src": "1281:7:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes16",+ "typeString": "bytes16"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 152,+ "name": "",+ "nodeType": "VariableDeclaration",+ "scope": 166,+ "src": "1290:11:0",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_array$_t_bytes2_$4_memory_$dyn_memory_ptr",+ "typeString": "bytes2[4][]"+ },+ "typeName": {+ "baseType": {+ "baseType": {+ "id": 148,+ "name": "bytes2",+ "nodeType": "ElementaryTypeName",+ "src": "1290:6:0",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes2",+ "typeString": "bytes2"+ }+ },+ "id": 150,+ "length": {+ "argumentTypes": null,+ "hexValue": "34",+ "id": 149,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "number",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "1297:1:0",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": null,+ "typeString": null+ },+ "value": "4"+ },+ "nodeType": "ArrayTypeName",+ "src": "1290:9:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_bytes2_$4_storage_ptr",+ "typeString": "bytes2[4]"+ }+ },+ "id": 151,+ "length": null,+ "nodeType": "ArrayTypeName",+ "src": "1290:11:0",+ "typeDescriptions": {+ "typeIdentifier": "t_array$_t_array$_t_bytes2_$4_storage_$dyn_storage_ptr",+ "typeString": "bytes2[4][]"+ }+ },+ "value": null,+ "visibility": "internal"+ }+ ],+ "src": "1231:71:0"+ },+ "scope": 167,+ "src": "1187:246:0",+ "stateMutability": "view",+ "superFunction": null,+ "visibility": "public"+ }+ ],+ "scope": 168,+ "src": "26:1413:0"+ }+ ],+ "src": "0:1440:0"+ },+ "compiler": {+ "name": "solc",+ "version": "0.4.24+commit.e67f0147.Emscripten.clang"+ },+ "networks": {},+ "schemaVersion": "2.0.1",+ "updatedAt": "2018-10-17T08:28:45.994Z"+}
+ test/contracts/Linearization.json view
@@ -0,0 +1,2716 @@+{+ "contractName": "Linearization",+ "abi": [+ {+ "anonymous": false,+ "inputs": [+ {+ "indexed": false,+ "name": "sender",+ "type": "address"+ },+ {+ "indexed": false,+ "name": "amount",+ "type": "uint256"+ }+ ],+ "name": "E1",+ "type": "event"+ },+ {+ "anonymous": false,+ "inputs": [+ {+ "indexed": false,+ "name": "tag",+ "type": "string"+ },+ {+ "indexed": false,+ "name": "uuid",+ "type": "bytes4"+ }+ ],+ "name": "E2",+ "type": "event"+ },+ {+ "anonymous": false,+ "inputs": [+ {+ "indexed": false,+ "name": "txOrigin",+ "type": "address"+ },+ {+ "indexed": false,+ "name": "blockNumber",+ "type": "uint256"+ }+ ],+ "name": "E3",+ "type": "event"+ },+ {+ "anonymous": false,+ "inputs": [+ {+ "indexed": false,+ "name": "sig",+ "type": "bytes4"+ },+ {+ "indexed": false,+ "name": "blockHash",+ "type": "bytes32"+ }+ ],+ "name": "E4",+ "type": "event"+ },+ {+ "constant": false,+ "inputs": [],+ "name": "e12",+ "outputs": [],+ "payable": false,+ "stateMutability": "nonpayable",+ "type": "function"+ },+ {+ "constant": false,+ "inputs": [],+ "name": "e21",+ "outputs": [],+ "payable": false,+ "stateMutability": "nonpayable",+ "type": "function"+ },+ {+ "constant": false,+ "inputs": [],+ "name": "e1",+ "outputs": [],+ "payable": false,+ "stateMutability": "nonpayable",+ "type": "function"+ },+ {+ "constant": false,+ "inputs": [],+ "name": "e2",+ "outputs": [],+ "payable": false,+ "stateMutability": "nonpayable",+ "type": "function"+ },+ {+ "constant": false,+ "inputs": [],+ "name": "e3",+ "outputs": [],+ "payable": false,+ "stateMutability": "nonpayable",+ "type": "function"+ },+ {+ "constant": false,+ "inputs": [],+ "name": "e4",+ "outputs": [],+ "payable": false,+ "stateMutability": "nonpayable",+ "type": "function"+ }+ ],+ "bytecode": "0x608060405234801561001057600080fd5b506105ad806100206000396000f300608060405260043610610077576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168062def0b21461007c57806356800b521461009357806379e5f054146100aa5780639b31f9e8146100c1578063a0f29798146100d8578063a2c2d666146100ef575b600080fd5b34801561008857600080fd5b50610091610106565b005b34801561009f57600080fd5b506100a8610226565b005b3480156100b657600080fd5b506100bf610293565b005b3480156100cd57600080fd5b506100d661033f565b005b3480156100e457600080fd5b506100ed6103f3565b005b3480156100fb57600080fd5b50610104610513565b005b7f39be10caf08413c53cba369135da2b641931c99ac27b0d821e26f3ec4e0c63d2336000604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a17fa7070e1659496fddc8e134f7c9c487aba246b54d9a23918210a30bfa32af9e4563deadbeef6040518080602001837c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001828103825260058152602001807f68656c6c6f0000000000000000000000000000000000000000000000000000008152506020019250505060405180910390a1565b7fe86793c401899b62baf9c8e9b8a8803ece6ace1021d056fe8634d1f59a0410c13243604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a1565b7fd8f3042e770b7de0dc534d3accbe98fba747e05ada6febe1a03d1e098521edc26000357fffffffff0000000000000000000000000000000000000000000000000000000016434060405180837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200182600019166000191681526020019250505060405180910390a1565b7fa7070e1659496fddc8e134f7c9c487aba246b54d9a23918210a30bfa32af9e4563deadbeef6040518080602001837c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001828103825260058152602001807f68656c6c6f0000000000000000000000000000000000000000000000000000008152506020019250505060405180910390a1565b7fa7070e1659496fddc8e134f7c9c487aba246b54d9a23918210a30bfa32af9e4563deadbeef6040518080602001837c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001828103825260058152602001807f68656c6c6f0000000000000000000000000000000000000000000000000000008152506020019250505060405180910390a17f39be10caf08413c53cba369135da2b641931c99ac27b0d821e26f3ec4e0c63d2336000604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a1565b7f39be10caf08413c53cba369135da2b641931c99ac27b0d821e26f3ec4e0c63d2336000604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a15600a165627a7a72305820be9afa4ce385da787f13197a249b8d9d1c557381e3c46f9bbada45913eee79870029",+ "deployedBytecode": "0x608060405260043610610077576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168062def0b21461007c57806356800b521461009357806379e5f054146100aa5780639b31f9e8146100c1578063a0f29798146100d8578063a2c2d666146100ef575b600080fd5b34801561008857600080fd5b50610091610106565b005b34801561009f57600080fd5b506100a8610226565b005b3480156100b657600080fd5b506100bf610293565b005b3480156100cd57600080fd5b506100d661033f565b005b3480156100e457600080fd5b506100ed6103f3565b005b3480156100fb57600080fd5b50610104610513565b005b7f39be10caf08413c53cba369135da2b641931c99ac27b0d821e26f3ec4e0c63d2336000604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a17fa7070e1659496fddc8e134f7c9c487aba246b54d9a23918210a30bfa32af9e4563deadbeef6040518080602001837c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001828103825260058152602001807f68656c6c6f0000000000000000000000000000000000000000000000000000008152506020019250505060405180910390a1565b7fe86793c401899b62baf9c8e9b8a8803ece6ace1021d056fe8634d1f59a0410c13243604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a1565b7fd8f3042e770b7de0dc534d3accbe98fba747e05ada6febe1a03d1e098521edc26000357fffffffff0000000000000000000000000000000000000000000000000000000016434060405180837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200182600019166000191681526020019250505060405180910390a1565b7fa7070e1659496fddc8e134f7c9c487aba246b54d9a23918210a30bfa32af9e4563deadbeef6040518080602001837c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001828103825260058152602001807f68656c6c6f0000000000000000000000000000000000000000000000000000008152506020019250505060405180910390a1565b7fa7070e1659496fddc8e134f7c9c487aba246b54d9a23918210a30bfa32af9e4563deadbeef6040518080602001837c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001828103825260058152602001807f68656c6c6f0000000000000000000000000000000000000000000000000000008152506020019250505060405180910390a17f39be10caf08413c53cba369135da2b641931c99ac27b0d821e26f3ec4e0c63d2336000604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a1565b7f39be10caf08413c53cba369135da2b641931c99ac27b0d821e26f3ec4e0c63d2336000604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a15600a165627a7a72305820be9afa4ce385da787f13197a249b8d9d1c557381e3c46f9bbada45913eee79870029",+ "sourceMap": "26:649:1:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;26:649:1;;;;;;;",+ "deployedSourceMap": "26:649:1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;224:89;;8:9:-1;5:2;;;30:1;27;20:12;5:2;224:89:1;;;;;;532:64;;8:9:-1;5:2;;;30:1;27;20:12;5:2;532:64:1;;;;;;600:73;;8:9:-1;5:2;;;30:1;27;20:12;5:2;600:73:1;;;;;;468:60;;8:9:-1;5:2;;;30:1;27;20:12;5:2;468:60:1;;;;;;317:89;;8:9:-1;5:2;;;30:1;27;20:12;5:2;317:89:1;;;;;;410:54;;8:9:-1;5:2;;;30:1;27;20:12;5:2;410:54:1;;;;;;224:89;257:17;260:10;272:1;257:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;285:23;297:10;285:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;224:89::o;532:64::-;564:27;567:9;578:12;564:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;532:64::o;600:73::-;632:36;635:7;;;;654:12;644:23;632:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;600:73::o;468:60::-;500:23;512:10;500:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;468:60::o;317:89::-;350:23;362:10;350:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;384:17;387:10;399:1;384:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;317:89::o;410:54::-;442:17;445:10;457:1;442:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;410:54::o",+ "source": "pragma solidity ^0.4.22;\n\ncontract Linearization {\n\n event E1(address sender, uint amount);\n event E2(string tag, bytes4 uuid);\n event E3(address txOrigin, uint blockNumber);\n event E4(bytes4 sig, bytes32 blockHash);\n\n function e12() public {\n emit E1(msg.sender, 0);\n emit E2(\"hello\", 0xdeadbeef);\n }\n\n function e21() public {\n emit E2(\"hello\", 0xdeadbeef);\n emit E1(msg.sender, 0);\n }\n\n function e1() public {\n emit E1(msg.sender, 0);\n }\n\n function e2() public {\n emit E2(\"hello\", 0xdeadbeef);\n }\n\n function e3() public {\n emit E3(tx.origin, block.number);\n }\n\n function e4() public {\n emit E4(msg.sig, blockhash(block.number));\n }\n}",+ "sourcePath": "/home/akru/hsweb3test/contracts/Linearization.sol",+ "ast": {+ "absolutePath": "/home/akru/hsweb3test/contracts/Linearization.sol",+ "exportedSymbols": {+ "Linearization": [+ 267+ ]+ },+ "id": 268,+ "nodeType": "SourceUnit",+ "nodes": [+ {+ "id": 169,+ "literals": [+ "solidity",+ "^",+ "0.4",+ ".22"+ ],+ "nodeType": "PragmaDirective",+ "src": "0:24:1"+ },+ {+ "baseContracts": [],+ "contractDependencies": [],+ "contractKind": "contract",+ "documentation": null,+ "fullyImplemented": true,+ "id": 267,+ "linearizedBaseContracts": [+ 267+ ],+ "name": "Linearization",+ "nodeType": "ContractDefinition",+ "nodes": [+ {+ "anonymous": false,+ "documentation": null,+ "id": 175,+ "name": "E1",+ "nodeType": "EventDefinition",+ "parameters": {+ "id": 174,+ "nodeType": "ParameterList",+ "parameters": [+ {+ "constant": false,+ "id": 171,+ "indexed": false,+ "name": "sender",+ "nodeType": "VariableDeclaration",+ "scope": 175,+ "src": "63:14:1",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_address",+ "typeString": "address"+ },+ "typeName": {+ "id": 170,+ "name": "address",+ "nodeType": "ElementaryTypeName",+ "src": "63:7:1",+ "typeDescriptions": {+ "typeIdentifier": "t_address",+ "typeString": "address"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 173,+ "indexed": false,+ "name": "amount",+ "nodeType": "VariableDeclaration",+ "scope": 175,+ "src": "79:11:1",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ },+ "typeName": {+ "id": 172,+ "name": "uint",+ "nodeType": "ElementaryTypeName",+ "src": "79:4:1",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "value": null,+ "visibility": "internal"+ }+ ],+ "src": "62:29:1"+ },+ "src": "54:38:1"+ },+ {+ "anonymous": false,+ "documentation": null,+ "id": 181,+ "name": "E2",+ "nodeType": "EventDefinition",+ "parameters": {+ "id": 180,+ "nodeType": "ParameterList",+ "parameters": [+ {+ "constant": false,+ "id": 177,+ "indexed": false,+ "name": "tag",+ "nodeType": "VariableDeclaration",+ "scope": 181,+ "src": "104:10:1",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_string_memory_ptr",+ "typeString": "string"+ },+ "typeName": {+ "id": 176,+ "name": "string",+ "nodeType": "ElementaryTypeName",+ "src": "104:6:1",+ "typeDescriptions": {+ "typeIdentifier": "t_string_storage_ptr",+ "typeString": "string"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 179,+ "indexed": false,+ "name": "uuid",+ "nodeType": "VariableDeclaration",+ "scope": 181,+ "src": "116:11:1",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes4",+ "typeString": "bytes4"+ },+ "typeName": {+ "id": 178,+ "name": "bytes4",+ "nodeType": "ElementaryTypeName",+ "src": "116:6:1",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes4",+ "typeString": "bytes4"+ }+ },+ "value": null,+ "visibility": "internal"+ }+ ],+ "src": "103:25:1"+ },+ "src": "95:34:1"+ },+ {+ "anonymous": false,+ "documentation": null,+ "id": 187,+ "name": "E3",+ "nodeType": "EventDefinition",+ "parameters": {+ "id": 186,+ "nodeType": "ParameterList",+ "parameters": [+ {+ "constant": false,+ "id": 183,+ "indexed": false,+ "name": "txOrigin",+ "nodeType": "VariableDeclaration",+ "scope": 187,+ "src": "141:16:1",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_address",+ "typeString": "address"+ },+ "typeName": {+ "id": 182,+ "name": "address",+ "nodeType": "ElementaryTypeName",+ "src": "141:7:1",+ "typeDescriptions": {+ "typeIdentifier": "t_address",+ "typeString": "address"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 185,+ "indexed": false,+ "name": "blockNumber",+ "nodeType": "VariableDeclaration",+ "scope": 187,+ "src": "159:16:1",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ },+ "typeName": {+ "id": 184,+ "name": "uint",+ "nodeType": "ElementaryTypeName",+ "src": "159:4:1",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "value": null,+ "visibility": "internal"+ }+ ],+ "src": "140:36:1"+ },+ "src": "132:45:1"+ },+ {+ "anonymous": false,+ "documentation": null,+ "id": 193,+ "name": "E4",+ "nodeType": "EventDefinition",+ "parameters": {+ "id": 192,+ "nodeType": "ParameterList",+ "parameters": [+ {+ "constant": false,+ "id": 189,+ "indexed": false,+ "name": "sig",+ "nodeType": "VariableDeclaration",+ "scope": 193,+ "src": "189:10:1",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes4",+ "typeString": "bytes4"+ },+ "typeName": {+ "id": 188,+ "name": "bytes4",+ "nodeType": "ElementaryTypeName",+ "src": "189:6:1",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes4",+ "typeString": "bytes4"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 191,+ "indexed": false,+ "name": "blockHash",+ "nodeType": "VariableDeclaration",+ "scope": 193,+ "src": "201:17:1",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes32",+ "typeString": "bytes32"+ },+ "typeName": {+ "id": 190,+ "name": "bytes32",+ "nodeType": "ElementaryTypeName",+ "src": "201:7:1",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes32",+ "typeString": "bytes32"+ }+ },+ "value": null,+ "visibility": "internal"+ }+ ],+ "src": "188:31:1"+ },+ "src": "180:40:1"+ },+ {+ "body": {+ "id": 207,+ "nodeType": "Block",+ "src": "246:67:1",+ "statements": [+ {+ "eventCall": {+ "argumentTypes": null,+ "arguments": [+ {+ "argumentTypes": null,+ "expression": {+ "argumentTypes": null,+ "id": 197,+ "name": "msg",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 381,+ "src": "260:3:1",+ "typeDescriptions": {+ "typeIdentifier": "t_magic_message",+ "typeString": "msg"+ }+ },+ "id": 198,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "memberName": "sender",+ "nodeType": "MemberAccess",+ "referencedDeclaration": null,+ "src": "260:10:1",+ "typeDescriptions": {+ "typeIdentifier": "t_address",+ "typeString": "address"+ }+ },+ {+ "argumentTypes": null,+ "hexValue": "30",+ "id": 199,+ "isConstant": false,+ "isLValue": false,+ "isPure": true,+ "kind": "number",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "272:1:1",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": "t_rational_0_by_1",+ "typeString": "int_const 0"+ },+ "value": "0"+ }+ ],+ "expression": {+ "argumentTypes": [+ {+ "typeIdentifier": "t_address",+ "typeString": "address"+ },+ {+ "typeIdentifier": "t_rational_0_by_1",+ "typeString": "int_const 0"+ }+ ],+ "id": 196,+ "name": "E1",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 175,+ "src": "257:2:1",+ "typeDescriptions": {+ "typeIdentifier": "t_function_event_nonpayable$_t_address_$_t_uint256_$returns$__$",+ "typeString": "function (address,uint256)"+ }+ },+ "id": 200,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "functionCall",+ "lValueRequested": false,+ "names": [],+ "nodeType": "FunctionCall",+ "src": "257:17:1",+ "typeDescriptions": {+ "typeIdentifier": "t_tuple$__$",+ "typeString": "tuple()"+ }+ },+ "id": 201,+ "nodeType": "EmitStatement",+ "src": "252:22:1"+ },+ {+ "eventCall": {+ "argumentTypes": null,+ "arguments": [+ {+ "argumentTypes": null,+ "hexValue": "68656c6c6f",+ "id": 203,+ "isConstant": false,+ "isLValue": false,+ "isPure": true,+ "kind": "string",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "288:7:1",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": "t_stringliteral_1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8",+ "typeString": "literal_string \"hello\""+ },+ "value": "hello"+ },+ {+ "argumentTypes": null,+ "hexValue": "30786465616462656566",+ "id": 204,+ "isConstant": false,+ "isLValue": false,+ "isPure": true,+ "kind": "number",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "297:10:1",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": "t_rational_3735928559_by_1",+ "typeString": "int_const 3735928559"+ },+ "value": "0xdeadbeef"+ }+ ],+ "expression": {+ "argumentTypes": [+ {+ "typeIdentifier": "t_stringliteral_1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8",+ "typeString": "literal_string \"hello\""+ },+ {+ "typeIdentifier": "t_rational_3735928559_by_1",+ "typeString": "int_const 3735928559"+ }+ ],+ "id": 202,+ "name": "E2",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 181,+ "src": "285:2:1",+ "typeDescriptions": {+ "typeIdentifier": "t_function_event_nonpayable$_t_string_memory_ptr_$_t_bytes4_$returns$__$",+ "typeString": "function (string memory,bytes4)"+ }+ },+ "id": 205,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "functionCall",+ "lValueRequested": false,+ "names": [],+ "nodeType": "FunctionCall",+ "src": "285:23:1",+ "typeDescriptions": {+ "typeIdentifier": "t_tuple$__$",+ "typeString": "tuple()"+ }+ },+ "id": 206,+ "nodeType": "EmitStatement",+ "src": "280:28:1"+ }+ ]+ },+ "documentation": null,+ "id": 208,+ "implemented": true,+ "isConstructor": false,+ "isDeclaredConst": false,+ "modifiers": [],+ "name": "e12",+ "nodeType": "FunctionDefinition",+ "parameters": {+ "id": 194,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "236:2:1"+ },+ "payable": false,+ "returnParameters": {+ "id": 195,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "246:0:1"+ },+ "scope": 267,+ "src": "224:89:1",+ "stateMutability": "nonpayable",+ "superFunction": null,+ "visibility": "public"+ },+ {+ "body": {+ "id": 222,+ "nodeType": "Block",+ "src": "339:67:1",+ "statements": [+ {+ "eventCall": {+ "argumentTypes": null,+ "arguments": [+ {+ "argumentTypes": null,+ "hexValue": "68656c6c6f",+ "id": 212,+ "isConstant": false,+ "isLValue": false,+ "isPure": true,+ "kind": "string",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "353:7:1",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": "t_stringliteral_1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8",+ "typeString": "literal_string \"hello\""+ },+ "value": "hello"+ },+ {+ "argumentTypes": null,+ "hexValue": "30786465616462656566",+ "id": 213,+ "isConstant": false,+ "isLValue": false,+ "isPure": true,+ "kind": "number",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "362:10:1",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": "t_rational_3735928559_by_1",+ "typeString": "int_const 3735928559"+ },+ "value": "0xdeadbeef"+ }+ ],+ "expression": {+ "argumentTypes": [+ {+ "typeIdentifier": "t_stringliteral_1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8",+ "typeString": "literal_string \"hello\""+ },+ {+ "typeIdentifier": "t_rational_3735928559_by_1",+ "typeString": "int_const 3735928559"+ }+ ],+ "id": 211,+ "name": "E2",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 181,+ "src": "350:2:1",+ "typeDescriptions": {+ "typeIdentifier": "t_function_event_nonpayable$_t_string_memory_ptr_$_t_bytes4_$returns$__$",+ "typeString": "function (string memory,bytes4)"+ }+ },+ "id": 214,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "functionCall",+ "lValueRequested": false,+ "names": [],+ "nodeType": "FunctionCall",+ "src": "350:23:1",+ "typeDescriptions": {+ "typeIdentifier": "t_tuple$__$",+ "typeString": "tuple()"+ }+ },+ "id": 215,+ "nodeType": "EmitStatement",+ "src": "345:28:1"+ },+ {+ "eventCall": {+ "argumentTypes": null,+ "arguments": [+ {+ "argumentTypes": null,+ "expression": {+ "argumentTypes": null,+ "id": 217,+ "name": "msg",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 381,+ "src": "387:3:1",+ "typeDescriptions": {+ "typeIdentifier": "t_magic_message",+ "typeString": "msg"+ }+ },+ "id": 218,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "memberName": "sender",+ "nodeType": "MemberAccess",+ "referencedDeclaration": null,+ "src": "387:10:1",+ "typeDescriptions": {+ "typeIdentifier": "t_address",+ "typeString": "address"+ }+ },+ {+ "argumentTypes": null,+ "hexValue": "30",+ "id": 219,+ "isConstant": false,+ "isLValue": false,+ "isPure": true,+ "kind": "number",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "399:1:1",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": "t_rational_0_by_1",+ "typeString": "int_const 0"+ },+ "value": "0"+ }+ ],+ "expression": {+ "argumentTypes": [+ {+ "typeIdentifier": "t_address",+ "typeString": "address"+ },+ {+ "typeIdentifier": "t_rational_0_by_1",+ "typeString": "int_const 0"+ }+ ],+ "id": 216,+ "name": "E1",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 175,+ "src": "384:2:1",+ "typeDescriptions": {+ "typeIdentifier": "t_function_event_nonpayable$_t_address_$_t_uint256_$returns$__$",+ "typeString": "function (address,uint256)"+ }+ },+ "id": 220,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "functionCall",+ "lValueRequested": false,+ "names": [],+ "nodeType": "FunctionCall",+ "src": "384:17:1",+ "typeDescriptions": {+ "typeIdentifier": "t_tuple$__$",+ "typeString": "tuple()"+ }+ },+ "id": 221,+ "nodeType": "EmitStatement",+ "src": "379:22:1"+ }+ ]+ },+ "documentation": null,+ "id": 223,+ "implemented": true,+ "isConstructor": false,+ "isDeclaredConst": false,+ "modifiers": [],+ "name": "e21",+ "nodeType": "FunctionDefinition",+ "parameters": {+ "id": 209,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "329:2:1"+ },+ "payable": false,+ "returnParameters": {+ "id": 210,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "339:0:1"+ },+ "scope": 267,+ "src": "317:89:1",+ "stateMutability": "nonpayable",+ "superFunction": null,+ "visibility": "public"+ },+ {+ "body": {+ "id": 232,+ "nodeType": "Block",+ "src": "431:33:1",+ "statements": [+ {+ "eventCall": {+ "argumentTypes": null,+ "arguments": [+ {+ "argumentTypes": null,+ "expression": {+ "argumentTypes": null,+ "id": 227,+ "name": "msg",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 381,+ "src": "445:3:1",+ "typeDescriptions": {+ "typeIdentifier": "t_magic_message",+ "typeString": "msg"+ }+ },+ "id": 228,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "memberName": "sender",+ "nodeType": "MemberAccess",+ "referencedDeclaration": null,+ "src": "445:10:1",+ "typeDescriptions": {+ "typeIdentifier": "t_address",+ "typeString": "address"+ }+ },+ {+ "argumentTypes": null,+ "hexValue": "30",+ "id": 229,+ "isConstant": false,+ "isLValue": false,+ "isPure": true,+ "kind": "number",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "457:1:1",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": "t_rational_0_by_1",+ "typeString": "int_const 0"+ },+ "value": "0"+ }+ ],+ "expression": {+ "argumentTypes": [+ {+ "typeIdentifier": "t_address",+ "typeString": "address"+ },+ {+ "typeIdentifier": "t_rational_0_by_1",+ "typeString": "int_const 0"+ }+ ],+ "id": 226,+ "name": "E1",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 175,+ "src": "442:2:1",+ "typeDescriptions": {+ "typeIdentifier": "t_function_event_nonpayable$_t_address_$_t_uint256_$returns$__$",+ "typeString": "function (address,uint256)"+ }+ },+ "id": 230,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "functionCall",+ "lValueRequested": false,+ "names": [],+ "nodeType": "FunctionCall",+ "src": "442:17:1",+ "typeDescriptions": {+ "typeIdentifier": "t_tuple$__$",+ "typeString": "tuple()"+ }+ },+ "id": 231,+ "nodeType": "EmitStatement",+ "src": "437:22:1"+ }+ ]+ },+ "documentation": null,+ "id": 233,+ "implemented": true,+ "isConstructor": false,+ "isDeclaredConst": false,+ "modifiers": [],+ "name": "e1",+ "nodeType": "FunctionDefinition",+ "parameters": {+ "id": 224,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "421:2:1"+ },+ "payable": false,+ "returnParameters": {+ "id": 225,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "431:0:1"+ },+ "scope": 267,+ "src": "410:54:1",+ "stateMutability": "nonpayable",+ "superFunction": null,+ "visibility": "public"+ },+ {+ "body": {+ "id": 241,+ "nodeType": "Block",+ "src": "489:39:1",+ "statements": [+ {+ "eventCall": {+ "argumentTypes": null,+ "arguments": [+ {+ "argumentTypes": null,+ "hexValue": "68656c6c6f",+ "id": 237,+ "isConstant": false,+ "isLValue": false,+ "isPure": true,+ "kind": "string",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "503:7:1",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": "t_stringliteral_1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8",+ "typeString": "literal_string \"hello\""+ },+ "value": "hello"+ },+ {+ "argumentTypes": null,+ "hexValue": "30786465616462656566",+ "id": 238,+ "isConstant": false,+ "isLValue": false,+ "isPure": true,+ "kind": "number",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "512:10:1",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": "t_rational_3735928559_by_1",+ "typeString": "int_const 3735928559"+ },+ "value": "0xdeadbeef"+ }+ ],+ "expression": {+ "argumentTypes": [+ {+ "typeIdentifier": "t_stringliteral_1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8",+ "typeString": "literal_string \"hello\""+ },+ {+ "typeIdentifier": "t_rational_3735928559_by_1",+ "typeString": "int_const 3735928559"+ }+ ],+ "id": 236,+ "name": "E2",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 181,+ "src": "500:2:1",+ "typeDescriptions": {+ "typeIdentifier": "t_function_event_nonpayable$_t_string_memory_ptr_$_t_bytes4_$returns$__$",+ "typeString": "function (string memory,bytes4)"+ }+ },+ "id": 239,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "functionCall",+ "lValueRequested": false,+ "names": [],+ "nodeType": "FunctionCall",+ "src": "500:23:1",+ "typeDescriptions": {+ "typeIdentifier": "t_tuple$__$",+ "typeString": "tuple()"+ }+ },+ "id": 240,+ "nodeType": "EmitStatement",+ "src": "495:28:1"+ }+ ]+ },+ "documentation": null,+ "id": 242,+ "implemented": true,+ "isConstructor": false,+ "isDeclaredConst": false,+ "modifiers": [],+ "name": "e2",+ "nodeType": "FunctionDefinition",+ "parameters": {+ "id": 234,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "479:2:1"+ },+ "payable": false,+ "returnParameters": {+ "id": 235,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "489:0:1"+ },+ "scope": 267,+ "src": "468:60:1",+ "stateMutability": "nonpayable",+ "superFunction": null,+ "visibility": "public"+ },+ {+ "body": {+ "id": 252,+ "nodeType": "Block",+ "src": "553:43:1",+ "statements": [+ {+ "eventCall": {+ "argumentTypes": null,+ "arguments": [+ {+ "argumentTypes": null,+ "expression": {+ "argumentTypes": null,+ "id": 246,+ "name": "tx",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 393,+ "src": "567:2:1",+ "typeDescriptions": {+ "typeIdentifier": "t_magic_transaction",+ "typeString": "tx"+ }+ },+ "id": 247,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "memberName": "origin",+ "nodeType": "MemberAccess",+ "referencedDeclaration": null,+ "src": "567:9:1",+ "typeDescriptions": {+ "typeIdentifier": "t_address",+ "typeString": "address"+ }+ },+ {+ "argumentTypes": null,+ "expression": {+ "argumentTypes": null,+ "id": 248,+ "name": "block",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 371,+ "src": "578:5:1",+ "typeDescriptions": {+ "typeIdentifier": "t_magic_block",+ "typeString": "block"+ }+ },+ "id": 249,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "memberName": "number",+ "nodeType": "MemberAccess",+ "referencedDeclaration": null,+ "src": "578:12:1",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ }+ ],+ "expression": {+ "argumentTypes": [+ {+ "typeIdentifier": "t_address",+ "typeString": "address"+ },+ {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ ],+ "id": 245,+ "name": "E3",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 187,+ "src": "564:2:1",+ "typeDescriptions": {+ "typeIdentifier": "t_function_event_nonpayable$_t_address_$_t_uint256_$returns$__$",+ "typeString": "function (address,uint256)"+ }+ },+ "id": 250,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "functionCall",+ "lValueRequested": false,+ "names": [],+ "nodeType": "FunctionCall",+ "src": "564:27:1",+ "typeDescriptions": {+ "typeIdentifier": "t_tuple$__$",+ "typeString": "tuple()"+ }+ },+ "id": 251,+ "nodeType": "EmitStatement",+ "src": "559:32:1"+ }+ ]+ },+ "documentation": null,+ "id": 253,+ "implemented": true,+ "isConstructor": false,+ "isDeclaredConst": false,+ "modifiers": [],+ "name": "e3",+ "nodeType": "FunctionDefinition",+ "parameters": {+ "id": 243,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "543:2:1"+ },+ "payable": false,+ "returnParameters": {+ "id": 244,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "553:0:1"+ },+ "scope": 267,+ "src": "532:64:1",+ "stateMutability": "nonpayable",+ "superFunction": null,+ "visibility": "public"+ },+ {+ "body": {+ "id": 265,+ "nodeType": "Block",+ "src": "621:52:1",+ "statements": [+ {+ "eventCall": {+ "argumentTypes": null,+ "arguments": [+ {+ "argumentTypes": null,+ "expression": {+ "argumentTypes": null,+ "id": 257,+ "name": "msg",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 381,+ "src": "635:3:1",+ "typeDescriptions": {+ "typeIdentifier": "t_magic_message",+ "typeString": "msg"+ }+ },+ "id": 258,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "memberName": "sig",+ "nodeType": "MemberAccess",+ "referencedDeclaration": null,+ "src": "635:7:1",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes4",+ "typeString": "bytes4"+ }+ },+ {+ "argumentTypes": null,+ "arguments": [+ {+ "argumentTypes": null,+ "expression": {+ "argumentTypes": null,+ "id": 260,+ "name": "block",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 371,+ "src": "654:5:1",+ "typeDescriptions": {+ "typeIdentifier": "t_magic_block",+ "typeString": "block"+ }+ },+ "id": 261,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "memberName": "number",+ "nodeType": "MemberAccess",+ "referencedDeclaration": null,+ "src": "654:12:1",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ }+ ],+ "expression": {+ "argumentTypes": [+ {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ ],+ "id": 259,+ "name": "blockhash",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 372,+ "src": "644:9:1",+ "typeDescriptions": {+ "typeIdentifier": "t_function_blockhash_view$_t_uint256_$returns$_t_bytes32_$",+ "typeString": "function (uint256) view returns (bytes32)"+ }+ },+ "id": 262,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "functionCall",+ "lValueRequested": false,+ "names": [],+ "nodeType": "FunctionCall",+ "src": "644:23:1",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes32",+ "typeString": "bytes32"+ }+ }+ ],+ "expression": {+ "argumentTypes": [+ {+ "typeIdentifier": "t_bytes4",+ "typeString": "bytes4"+ },+ {+ "typeIdentifier": "t_bytes32",+ "typeString": "bytes32"+ }+ ],+ "id": 256,+ "name": "E4",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 193,+ "src": "632:2:1",+ "typeDescriptions": {+ "typeIdentifier": "t_function_event_nonpayable$_t_bytes4_$_t_bytes32_$returns$__$",+ "typeString": "function (bytes4,bytes32)"+ }+ },+ "id": 263,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "functionCall",+ "lValueRequested": false,+ "names": [],+ "nodeType": "FunctionCall",+ "src": "632:36:1",+ "typeDescriptions": {+ "typeIdentifier": "t_tuple$__$",+ "typeString": "tuple()"+ }+ },+ "id": 264,+ "nodeType": "EmitStatement",+ "src": "627:41:1"+ }+ ]+ },+ "documentation": null,+ "id": 266,+ "implemented": true,+ "isConstructor": false,+ "isDeclaredConst": false,+ "modifiers": [],+ "name": "e4",+ "nodeType": "FunctionDefinition",+ "parameters": {+ "id": 254,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "611:2:1"+ },+ "payable": false,+ "returnParameters": {+ "id": 255,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "621:0:1"+ },+ "scope": 267,+ "src": "600:73:1",+ "stateMutability": "nonpayable",+ "superFunction": null,+ "visibility": "public"+ }+ ],+ "scope": 268,+ "src": "26:649:1"+ }+ ],+ "src": "0:675:1"+ },+ "legacyAST": {+ "absolutePath": "/home/akru/hsweb3test/contracts/Linearization.sol",+ "exportedSymbols": {+ "Linearization": [+ 267+ ]+ },+ "id": 268,+ "nodeType": "SourceUnit",+ "nodes": [+ {+ "id": 169,+ "literals": [+ "solidity",+ "^",+ "0.4",+ ".22"+ ],+ "nodeType": "PragmaDirective",+ "src": "0:24:1"+ },+ {+ "baseContracts": [],+ "contractDependencies": [],+ "contractKind": "contract",+ "documentation": null,+ "fullyImplemented": true,+ "id": 267,+ "linearizedBaseContracts": [+ 267+ ],+ "name": "Linearization",+ "nodeType": "ContractDefinition",+ "nodes": [+ {+ "anonymous": false,+ "documentation": null,+ "id": 175,+ "name": "E1",+ "nodeType": "EventDefinition",+ "parameters": {+ "id": 174,+ "nodeType": "ParameterList",+ "parameters": [+ {+ "constant": false,+ "id": 171,+ "indexed": false,+ "name": "sender",+ "nodeType": "VariableDeclaration",+ "scope": 175,+ "src": "63:14:1",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_address",+ "typeString": "address"+ },+ "typeName": {+ "id": 170,+ "name": "address",+ "nodeType": "ElementaryTypeName",+ "src": "63:7:1",+ "typeDescriptions": {+ "typeIdentifier": "t_address",+ "typeString": "address"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 173,+ "indexed": false,+ "name": "amount",+ "nodeType": "VariableDeclaration",+ "scope": 175,+ "src": "79:11:1",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ },+ "typeName": {+ "id": 172,+ "name": "uint",+ "nodeType": "ElementaryTypeName",+ "src": "79:4:1",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "value": null,+ "visibility": "internal"+ }+ ],+ "src": "62:29:1"+ },+ "src": "54:38:1"+ },+ {+ "anonymous": false,+ "documentation": null,+ "id": 181,+ "name": "E2",+ "nodeType": "EventDefinition",+ "parameters": {+ "id": 180,+ "nodeType": "ParameterList",+ "parameters": [+ {+ "constant": false,+ "id": 177,+ "indexed": false,+ "name": "tag",+ "nodeType": "VariableDeclaration",+ "scope": 181,+ "src": "104:10:1",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_string_memory_ptr",+ "typeString": "string"+ },+ "typeName": {+ "id": 176,+ "name": "string",+ "nodeType": "ElementaryTypeName",+ "src": "104:6:1",+ "typeDescriptions": {+ "typeIdentifier": "t_string_storage_ptr",+ "typeString": "string"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 179,+ "indexed": false,+ "name": "uuid",+ "nodeType": "VariableDeclaration",+ "scope": 181,+ "src": "116:11:1",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes4",+ "typeString": "bytes4"+ },+ "typeName": {+ "id": 178,+ "name": "bytes4",+ "nodeType": "ElementaryTypeName",+ "src": "116:6:1",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes4",+ "typeString": "bytes4"+ }+ },+ "value": null,+ "visibility": "internal"+ }+ ],+ "src": "103:25:1"+ },+ "src": "95:34:1"+ },+ {+ "anonymous": false,+ "documentation": null,+ "id": 187,+ "name": "E3",+ "nodeType": "EventDefinition",+ "parameters": {+ "id": 186,+ "nodeType": "ParameterList",+ "parameters": [+ {+ "constant": false,+ "id": 183,+ "indexed": false,+ "name": "txOrigin",+ "nodeType": "VariableDeclaration",+ "scope": 187,+ "src": "141:16:1",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_address",+ "typeString": "address"+ },+ "typeName": {+ "id": 182,+ "name": "address",+ "nodeType": "ElementaryTypeName",+ "src": "141:7:1",+ "typeDescriptions": {+ "typeIdentifier": "t_address",+ "typeString": "address"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 185,+ "indexed": false,+ "name": "blockNumber",+ "nodeType": "VariableDeclaration",+ "scope": 187,+ "src": "159:16:1",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ },+ "typeName": {+ "id": 184,+ "name": "uint",+ "nodeType": "ElementaryTypeName",+ "src": "159:4:1",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "value": null,+ "visibility": "internal"+ }+ ],+ "src": "140:36:1"+ },+ "src": "132:45:1"+ },+ {+ "anonymous": false,+ "documentation": null,+ "id": 193,+ "name": "E4",+ "nodeType": "EventDefinition",+ "parameters": {+ "id": 192,+ "nodeType": "ParameterList",+ "parameters": [+ {+ "constant": false,+ "id": 189,+ "indexed": false,+ "name": "sig",+ "nodeType": "VariableDeclaration",+ "scope": 193,+ "src": "189:10:1",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes4",+ "typeString": "bytes4"+ },+ "typeName": {+ "id": 188,+ "name": "bytes4",+ "nodeType": "ElementaryTypeName",+ "src": "189:6:1",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes4",+ "typeString": "bytes4"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 191,+ "indexed": false,+ "name": "blockHash",+ "nodeType": "VariableDeclaration",+ "scope": 193,+ "src": "201:17:1",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes32",+ "typeString": "bytes32"+ },+ "typeName": {+ "id": 190,+ "name": "bytes32",+ "nodeType": "ElementaryTypeName",+ "src": "201:7:1",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes32",+ "typeString": "bytes32"+ }+ },+ "value": null,+ "visibility": "internal"+ }+ ],+ "src": "188:31:1"+ },+ "src": "180:40:1"+ },+ {+ "body": {+ "id": 207,+ "nodeType": "Block",+ "src": "246:67:1",+ "statements": [+ {+ "eventCall": {+ "argumentTypes": null,+ "arguments": [+ {+ "argumentTypes": null,+ "expression": {+ "argumentTypes": null,+ "id": 197,+ "name": "msg",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 381,+ "src": "260:3:1",+ "typeDescriptions": {+ "typeIdentifier": "t_magic_message",+ "typeString": "msg"+ }+ },+ "id": 198,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "memberName": "sender",+ "nodeType": "MemberAccess",+ "referencedDeclaration": null,+ "src": "260:10:1",+ "typeDescriptions": {+ "typeIdentifier": "t_address",+ "typeString": "address"+ }+ },+ {+ "argumentTypes": null,+ "hexValue": "30",+ "id": 199,+ "isConstant": false,+ "isLValue": false,+ "isPure": true,+ "kind": "number",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "272:1:1",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": "t_rational_0_by_1",+ "typeString": "int_const 0"+ },+ "value": "0"+ }+ ],+ "expression": {+ "argumentTypes": [+ {+ "typeIdentifier": "t_address",+ "typeString": "address"+ },+ {+ "typeIdentifier": "t_rational_0_by_1",+ "typeString": "int_const 0"+ }+ ],+ "id": 196,+ "name": "E1",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 175,+ "src": "257:2:1",+ "typeDescriptions": {+ "typeIdentifier": "t_function_event_nonpayable$_t_address_$_t_uint256_$returns$__$",+ "typeString": "function (address,uint256)"+ }+ },+ "id": 200,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "functionCall",+ "lValueRequested": false,+ "names": [],+ "nodeType": "FunctionCall",+ "src": "257:17:1",+ "typeDescriptions": {+ "typeIdentifier": "t_tuple$__$",+ "typeString": "tuple()"+ }+ },+ "id": 201,+ "nodeType": "EmitStatement",+ "src": "252:22:1"+ },+ {+ "eventCall": {+ "argumentTypes": null,+ "arguments": [+ {+ "argumentTypes": null,+ "hexValue": "68656c6c6f",+ "id": 203,+ "isConstant": false,+ "isLValue": false,+ "isPure": true,+ "kind": "string",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "288:7:1",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": "t_stringliteral_1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8",+ "typeString": "literal_string \"hello\""+ },+ "value": "hello"+ },+ {+ "argumentTypes": null,+ "hexValue": "30786465616462656566",+ "id": 204,+ "isConstant": false,+ "isLValue": false,+ "isPure": true,+ "kind": "number",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "297:10:1",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": "t_rational_3735928559_by_1",+ "typeString": "int_const 3735928559"+ },+ "value": "0xdeadbeef"+ }+ ],+ "expression": {+ "argumentTypes": [+ {+ "typeIdentifier": "t_stringliteral_1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8",+ "typeString": "literal_string \"hello\""+ },+ {+ "typeIdentifier": "t_rational_3735928559_by_1",+ "typeString": "int_const 3735928559"+ }+ ],+ "id": 202,+ "name": "E2",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 181,+ "src": "285:2:1",+ "typeDescriptions": {+ "typeIdentifier": "t_function_event_nonpayable$_t_string_memory_ptr_$_t_bytes4_$returns$__$",+ "typeString": "function (string memory,bytes4)"+ }+ },+ "id": 205,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "functionCall",+ "lValueRequested": false,+ "names": [],+ "nodeType": "FunctionCall",+ "src": "285:23:1",+ "typeDescriptions": {+ "typeIdentifier": "t_tuple$__$",+ "typeString": "tuple()"+ }+ },+ "id": 206,+ "nodeType": "EmitStatement",+ "src": "280:28:1"+ }+ ]+ },+ "documentation": null,+ "id": 208,+ "implemented": true,+ "isConstructor": false,+ "isDeclaredConst": false,+ "modifiers": [],+ "name": "e12",+ "nodeType": "FunctionDefinition",+ "parameters": {+ "id": 194,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "236:2:1"+ },+ "payable": false,+ "returnParameters": {+ "id": 195,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "246:0:1"+ },+ "scope": 267,+ "src": "224:89:1",+ "stateMutability": "nonpayable",+ "superFunction": null,+ "visibility": "public"+ },+ {+ "body": {+ "id": 222,+ "nodeType": "Block",+ "src": "339:67:1",+ "statements": [+ {+ "eventCall": {+ "argumentTypes": null,+ "arguments": [+ {+ "argumentTypes": null,+ "hexValue": "68656c6c6f",+ "id": 212,+ "isConstant": false,+ "isLValue": false,+ "isPure": true,+ "kind": "string",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "353:7:1",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": "t_stringliteral_1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8",+ "typeString": "literal_string \"hello\""+ },+ "value": "hello"+ },+ {+ "argumentTypes": null,+ "hexValue": "30786465616462656566",+ "id": 213,+ "isConstant": false,+ "isLValue": false,+ "isPure": true,+ "kind": "number",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "362:10:1",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": "t_rational_3735928559_by_1",+ "typeString": "int_const 3735928559"+ },+ "value": "0xdeadbeef"+ }+ ],+ "expression": {+ "argumentTypes": [+ {+ "typeIdentifier": "t_stringliteral_1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8",+ "typeString": "literal_string \"hello\""+ },+ {+ "typeIdentifier": "t_rational_3735928559_by_1",+ "typeString": "int_const 3735928559"+ }+ ],+ "id": 211,+ "name": "E2",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 181,+ "src": "350:2:1",+ "typeDescriptions": {+ "typeIdentifier": "t_function_event_nonpayable$_t_string_memory_ptr_$_t_bytes4_$returns$__$",+ "typeString": "function (string memory,bytes4)"+ }+ },+ "id": 214,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "functionCall",+ "lValueRequested": false,+ "names": [],+ "nodeType": "FunctionCall",+ "src": "350:23:1",+ "typeDescriptions": {+ "typeIdentifier": "t_tuple$__$",+ "typeString": "tuple()"+ }+ },+ "id": 215,+ "nodeType": "EmitStatement",+ "src": "345:28:1"+ },+ {+ "eventCall": {+ "argumentTypes": null,+ "arguments": [+ {+ "argumentTypes": null,+ "expression": {+ "argumentTypes": null,+ "id": 217,+ "name": "msg",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 381,+ "src": "387:3:1",+ "typeDescriptions": {+ "typeIdentifier": "t_magic_message",+ "typeString": "msg"+ }+ },+ "id": 218,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "memberName": "sender",+ "nodeType": "MemberAccess",+ "referencedDeclaration": null,+ "src": "387:10:1",+ "typeDescriptions": {+ "typeIdentifier": "t_address",+ "typeString": "address"+ }+ },+ {+ "argumentTypes": null,+ "hexValue": "30",+ "id": 219,+ "isConstant": false,+ "isLValue": false,+ "isPure": true,+ "kind": "number",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "399:1:1",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": "t_rational_0_by_1",+ "typeString": "int_const 0"+ },+ "value": "0"+ }+ ],+ "expression": {+ "argumentTypes": [+ {+ "typeIdentifier": "t_address",+ "typeString": "address"+ },+ {+ "typeIdentifier": "t_rational_0_by_1",+ "typeString": "int_const 0"+ }+ ],+ "id": 216,+ "name": "E1",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 175,+ "src": "384:2:1",+ "typeDescriptions": {+ "typeIdentifier": "t_function_event_nonpayable$_t_address_$_t_uint256_$returns$__$",+ "typeString": "function (address,uint256)"+ }+ },+ "id": 220,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "functionCall",+ "lValueRequested": false,+ "names": [],+ "nodeType": "FunctionCall",+ "src": "384:17:1",+ "typeDescriptions": {+ "typeIdentifier": "t_tuple$__$",+ "typeString": "tuple()"+ }+ },+ "id": 221,+ "nodeType": "EmitStatement",+ "src": "379:22:1"+ }+ ]+ },+ "documentation": null,+ "id": 223,+ "implemented": true,+ "isConstructor": false,+ "isDeclaredConst": false,+ "modifiers": [],+ "name": "e21",+ "nodeType": "FunctionDefinition",+ "parameters": {+ "id": 209,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "329:2:1"+ },+ "payable": false,+ "returnParameters": {+ "id": 210,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "339:0:1"+ },+ "scope": 267,+ "src": "317:89:1",+ "stateMutability": "nonpayable",+ "superFunction": null,+ "visibility": "public"+ },+ {+ "body": {+ "id": 232,+ "nodeType": "Block",+ "src": "431:33:1",+ "statements": [+ {+ "eventCall": {+ "argumentTypes": null,+ "arguments": [+ {+ "argumentTypes": null,+ "expression": {+ "argumentTypes": null,+ "id": 227,+ "name": "msg",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 381,+ "src": "445:3:1",+ "typeDescriptions": {+ "typeIdentifier": "t_magic_message",+ "typeString": "msg"+ }+ },+ "id": 228,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "memberName": "sender",+ "nodeType": "MemberAccess",+ "referencedDeclaration": null,+ "src": "445:10:1",+ "typeDescriptions": {+ "typeIdentifier": "t_address",+ "typeString": "address"+ }+ },+ {+ "argumentTypes": null,+ "hexValue": "30",+ "id": 229,+ "isConstant": false,+ "isLValue": false,+ "isPure": true,+ "kind": "number",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "457:1:1",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": "t_rational_0_by_1",+ "typeString": "int_const 0"+ },+ "value": "0"+ }+ ],+ "expression": {+ "argumentTypes": [+ {+ "typeIdentifier": "t_address",+ "typeString": "address"+ },+ {+ "typeIdentifier": "t_rational_0_by_1",+ "typeString": "int_const 0"+ }+ ],+ "id": 226,+ "name": "E1",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 175,+ "src": "442:2:1",+ "typeDescriptions": {+ "typeIdentifier": "t_function_event_nonpayable$_t_address_$_t_uint256_$returns$__$",+ "typeString": "function (address,uint256)"+ }+ },+ "id": 230,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "functionCall",+ "lValueRequested": false,+ "names": [],+ "nodeType": "FunctionCall",+ "src": "442:17:1",+ "typeDescriptions": {+ "typeIdentifier": "t_tuple$__$",+ "typeString": "tuple()"+ }+ },+ "id": 231,+ "nodeType": "EmitStatement",+ "src": "437:22:1"+ }+ ]+ },+ "documentation": null,+ "id": 233,+ "implemented": true,+ "isConstructor": false,+ "isDeclaredConst": false,+ "modifiers": [],+ "name": "e1",+ "nodeType": "FunctionDefinition",+ "parameters": {+ "id": 224,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "421:2:1"+ },+ "payable": false,+ "returnParameters": {+ "id": 225,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "431:0:1"+ },+ "scope": 267,+ "src": "410:54:1",+ "stateMutability": "nonpayable",+ "superFunction": null,+ "visibility": "public"+ },+ {+ "body": {+ "id": 241,+ "nodeType": "Block",+ "src": "489:39:1",+ "statements": [+ {+ "eventCall": {+ "argumentTypes": null,+ "arguments": [+ {+ "argumentTypes": null,+ "hexValue": "68656c6c6f",+ "id": 237,+ "isConstant": false,+ "isLValue": false,+ "isPure": true,+ "kind": "string",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "503:7:1",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": "t_stringliteral_1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8",+ "typeString": "literal_string \"hello\""+ },+ "value": "hello"+ },+ {+ "argumentTypes": null,+ "hexValue": "30786465616462656566",+ "id": 238,+ "isConstant": false,+ "isLValue": false,+ "isPure": true,+ "kind": "number",+ "lValueRequested": false,+ "nodeType": "Literal",+ "src": "512:10:1",+ "subdenomination": null,+ "typeDescriptions": {+ "typeIdentifier": "t_rational_3735928559_by_1",+ "typeString": "int_const 3735928559"+ },+ "value": "0xdeadbeef"+ }+ ],+ "expression": {+ "argumentTypes": [+ {+ "typeIdentifier": "t_stringliteral_1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8",+ "typeString": "literal_string \"hello\""+ },+ {+ "typeIdentifier": "t_rational_3735928559_by_1",+ "typeString": "int_const 3735928559"+ }+ ],+ "id": 236,+ "name": "E2",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 181,+ "src": "500:2:1",+ "typeDescriptions": {+ "typeIdentifier": "t_function_event_nonpayable$_t_string_memory_ptr_$_t_bytes4_$returns$__$",+ "typeString": "function (string memory,bytes4)"+ }+ },+ "id": 239,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "functionCall",+ "lValueRequested": false,+ "names": [],+ "nodeType": "FunctionCall",+ "src": "500:23:1",+ "typeDescriptions": {+ "typeIdentifier": "t_tuple$__$",+ "typeString": "tuple()"+ }+ },+ "id": 240,+ "nodeType": "EmitStatement",+ "src": "495:28:1"+ }+ ]+ },+ "documentation": null,+ "id": 242,+ "implemented": true,+ "isConstructor": false,+ "isDeclaredConst": false,+ "modifiers": [],+ "name": "e2",+ "nodeType": "FunctionDefinition",+ "parameters": {+ "id": 234,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "479:2:1"+ },+ "payable": false,+ "returnParameters": {+ "id": 235,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "489:0:1"+ },+ "scope": 267,+ "src": "468:60:1",+ "stateMutability": "nonpayable",+ "superFunction": null,+ "visibility": "public"+ },+ {+ "body": {+ "id": 252,+ "nodeType": "Block",+ "src": "553:43:1",+ "statements": [+ {+ "eventCall": {+ "argumentTypes": null,+ "arguments": [+ {+ "argumentTypes": null,+ "expression": {+ "argumentTypes": null,+ "id": 246,+ "name": "tx",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 393,+ "src": "567:2:1",+ "typeDescriptions": {+ "typeIdentifier": "t_magic_transaction",+ "typeString": "tx"+ }+ },+ "id": 247,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "memberName": "origin",+ "nodeType": "MemberAccess",+ "referencedDeclaration": null,+ "src": "567:9:1",+ "typeDescriptions": {+ "typeIdentifier": "t_address",+ "typeString": "address"+ }+ },+ {+ "argumentTypes": null,+ "expression": {+ "argumentTypes": null,+ "id": 248,+ "name": "block",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 371,+ "src": "578:5:1",+ "typeDescriptions": {+ "typeIdentifier": "t_magic_block",+ "typeString": "block"+ }+ },+ "id": 249,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "memberName": "number",+ "nodeType": "MemberAccess",+ "referencedDeclaration": null,+ "src": "578:12:1",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ }+ ],+ "expression": {+ "argumentTypes": [+ {+ "typeIdentifier": "t_address",+ "typeString": "address"+ },+ {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ ],+ "id": 245,+ "name": "E3",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 187,+ "src": "564:2:1",+ "typeDescriptions": {+ "typeIdentifier": "t_function_event_nonpayable$_t_address_$_t_uint256_$returns$__$",+ "typeString": "function (address,uint256)"+ }+ },+ "id": 250,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "functionCall",+ "lValueRequested": false,+ "names": [],+ "nodeType": "FunctionCall",+ "src": "564:27:1",+ "typeDescriptions": {+ "typeIdentifier": "t_tuple$__$",+ "typeString": "tuple()"+ }+ },+ "id": 251,+ "nodeType": "EmitStatement",+ "src": "559:32:1"+ }+ ]+ },+ "documentation": null,+ "id": 253,+ "implemented": true,+ "isConstructor": false,+ "isDeclaredConst": false,+ "modifiers": [],+ "name": "e3",+ "nodeType": "FunctionDefinition",+ "parameters": {+ "id": 243,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "543:2:1"+ },+ "payable": false,+ "returnParameters": {+ "id": 244,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "553:0:1"+ },+ "scope": 267,+ "src": "532:64:1",+ "stateMutability": "nonpayable",+ "superFunction": null,+ "visibility": "public"+ },+ {+ "body": {+ "id": 265,+ "nodeType": "Block",+ "src": "621:52:1",+ "statements": [+ {+ "eventCall": {+ "argumentTypes": null,+ "arguments": [+ {+ "argumentTypes": null,+ "expression": {+ "argumentTypes": null,+ "id": 257,+ "name": "msg",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 381,+ "src": "635:3:1",+ "typeDescriptions": {+ "typeIdentifier": "t_magic_message",+ "typeString": "msg"+ }+ },+ "id": 258,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "memberName": "sig",+ "nodeType": "MemberAccess",+ "referencedDeclaration": null,+ "src": "635:7:1",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes4",+ "typeString": "bytes4"+ }+ },+ {+ "argumentTypes": null,+ "arguments": [+ {+ "argumentTypes": null,+ "expression": {+ "argumentTypes": null,+ "id": 260,+ "name": "block",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 371,+ "src": "654:5:1",+ "typeDescriptions": {+ "typeIdentifier": "t_magic_block",+ "typeString": "block"+ }+ },+ "id": 261,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "memberName": "number",+ "nodeType": "MemberAccess",+ "referencedDeclaration": null,+ "src": "654:12:1",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ }+ ],+ "expression": {+ "argumentTypes": [+ {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ ],+ "id": 259,+ "name": "blockhash",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 372,+ "src": "644:9:1",+ "typeDescriptions": {+ "typeIdentifier": "t_function_blockhash_view$_t_uint256_$returns$_t_bytes32_$",+ "typeString": "function (uint256) view returns (bytes32)"+ }+ },+ "id": 262,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "functionCall",+ "lValueRequested": false,+ "names": [],+ "nodeType": "FunctionCall",+ "src": "644:23:1",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes32",+ "typeString": "bytes32"+ }+ }+ ],+ "expression": {+ "argumentTypes": [+ {+ "typeIdentifier": "t_bytes4",+ "typeString": "bytes4"+ },+ {+ "typeIdentifier": "t_bytes32",+ "typeString": "bytes32"+ }+ ],+ "id": 256,+ "name": "E4",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 193,+ "src": "632:2:1",+ "typeDescriptions": {+ "typeIdentifier": "t_function_event_nonpayable$_t_bytes4_$_t_bytes32_$returns$__$",+ "typeString": "function (bytes4,bytes32)"+ }+ },+ "id": 263,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "functionCall",+ "lValueRequested": false,+ "names": [],+ "nodeType": "FunctionCall",+ "src": "632:36:1",+ "typeDescriptions": {+ "typeIdentifier": "t_tuple$__$",+ "typeString": "tuple()"+ }+ },+ "id": 264,+ "nodeType": "EmitStatement",+ "src": "627:41:1"+ }+ ]+ },+ "documentation": null,+ "id": 266,+ "implemented": true,+ "isConstructor": false,+ "isDeclaredConst": false,+ "modifiers": [],+ "name": "e4",+ "nodeType": "FunctionDefinition",+ "parameters": {+ "id": 254,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "611:2:1"+ },+ "payable": false,+ "returnParameters": {+ "id": 255,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "621:0:1"+ },+ "scope": 267,+ "src": "600:73:1",+ "stateMutability": "nonpayable",+ "superFunction": null,+ "visibility": "public"+ }+ ],+ "scope": 268,+ "src": "26:649:1"+ }+ ],+ "src": "0:675:1"+ },+ "compiler": {+ "name": "solc",+ "version": "0.4.24+commit.e67f0147.Emscripten.clang"+ },+ "networks": {},+ "schemaVersion": "2.0.1",+ "updatedAt": "2018-10-17T08:27:57.791Z"+}
+ test/contracts/Registry.json view
@@ -0,0 +1,506 @@+{+ "contractName": "Registry",+ "abi": [+ {+ "anonymous": false,+ "inputs": [+ {+ "indexed": true,+ "name": "listingHash",+ "type": "bytes32"+ }+ ],+ "name": "A",+ "type": "event"+ },+ {+ "anonymous": false,+ "inputs": [+ {+ "indexed": true,+ "name": "sender",+ "type": "address"+ },+ {+ "indexed": false,+ "name": "listingHash",+ "type": "bytes32"+ }+ ],+ "name": "B",+ "type": "event"+ },+ {+ "anonymous": false,+ "inputs": [+ {+ "indexed": false,+ "name": "dog",+ "type": "address"+ },+ {+ "indexed": false,+ "name": "cat",+ "type": "bytes32"+ }+ ],+ "name": "C",+ "type": "event"+ }+ ],+ "bytecode": "0x6080604052348015600f57600080fd5b50603580601d6000396000f3006080604052600080fd00a165627a7a7230582033480aa8fef567c80a4f8afd205add18d07c6a0f6991c2a4b0c2c20b8220f89b0029",+ "deployedBytecode": "0x6080604052600080fd00a165627a7a7230582033480aa8fef567c80a4f8afd205add18d07c6a0f6991c2a4b0c2c20b8220f89b0029",+ "sourceMap": "26:163:3:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;26:163:3;;;;;;;",+ "deployedSourceMap": "26:163:3:-;;;;;",+ "source": "pragma solidity ^0.4.22;\n\ncontract Registry {\n\n\n event A(bytes32 indexed listingHash);\n event B(address indexed sender, bytes32 listingHash);\n event C(address dog, bytes32 cat);\n\n}\n",+ "sourcePath": "/home/akru/hsweb3test/contracts/Registry.sol",+ "ast": {+ "absolutePath": "/home/akru/hsweb3test/contracts/Registry.sol",+ "exportedSymbols": {+ "Registry": [+ 343+ ]+ },+ "id": 344,+ "nodeType": "SourceUnit",+ "nodes": [+ {+ "id": 326,+ "literals": [+ "solidity",+ "^",+ "0.4",+ ".22"+ ],+ "nodeType": "PragmaDirective",+ "src": "0:24:3"+ },+ {+ "baseContracts": [],+ "contractDependencies": [],+ "contractKind": "contract",+ "documentation": null,+ "fullyImplemented": true,+ "id": 343,+ "linearizedBaseContracts": [+ 343+ ],+ "name": "Registry",+ "nodeType": "ContractDefinition",+ "nodes": [+ {+ "anonymous": false,+ "documentation": null,+ "id": 330,+ "name": "A",+ "nodeType": "EventDefinition",+ "parameters": {+ "id": 329,+ "nodeType": "ParameterList",+ "parameters": [+ {+ "constant": false,+ "id": 328,+ "indexed": true,+ "name": "listingHash",+ "nodeType": "VariableDeclaration",+ "scope": 330,+ "src": "60:27:3",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes32",+ "typeString": "bytes32"+ },+ "typeName": {+ "id": 327,+ "name": "bytes32",+ "nodeType": "ElementaryTypeName",+ "src": "60:7:3",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes32",+ "typeString": "bytes32"+ }+ },+ "value": null,+ "visibility": "internal"+ }+ ],+ "src": "59:29:3"+ },+ "src": "52:37:3"+ },+ {+ "anonymous": false,+ "documentation": null,+ "id": 336,+ "name": "B",+ "nodeType": "EventDefinition",+ "parameters": {+ "id": 335,+ "nodeType": "ParameterList",+ "parameters": [+ {+ "constant": false,+ "id": 332,+ "indexed": true,+ "name": "sender",+ "nodeType": "VariableDeclaration",+ "scope": 336,+ "src": "102:22:3",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_address",+ "typeString": "address"+ },+ "typeName": {+ "id": 331,+ "name": "address",+ "nodeType": "ElementaryTypeName",+ "src": "102:7:3",+ "typeDescriptions": {+ "typeIdentifier": "t_address",+ "typeString": "address"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 334,+ "indexed": false,+ "name": "listingHash",+ "nodeType": "VariableDeclaration",+ "scope": 336,+ "src": "126:19:3",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes32",+ "typeString": "bytes32"+ },+ "typeName": {+ "id": 333,+ "name": "bytes32",+ "nodeType": "ElementaryTypeName",+ "src": "126:7:3",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes32",+ "typeString": "bytes32"+ }+ },+ "value": null,+ "visibility": "internal"+ }+ ],+ "src": "101:45:3"+ },+ "src": "94:53:3"+ },+ {+ "anonymous": false,+ "documentation": null,+ "id": 342,+ "name": "C",+ "nodeType": "EventDefinition",+ "parameters": {+ "id": 341,+ "nodeType": "ParameterList",+ "parameters": [+ {+ "constant": false,+ "id": 338,+ "indexed": false,+ "name": "dog",+ "nodeType": "VariableDeclaration",+ "scope": 342,+ "src": "160:11:3",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_address",+ "typeString": "address"+ },+ "typeName": {+ "id": 337,+ "name": "address",+ "nodeType": "ElementaryTypeName",+ "src": "160:7:3",+ "typeDescriptions": {+ "typeIdentifier": "t_address",+ "typeString": "address"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 340,+ "indexed": false,+ "name": "cat",+ "nodeType": "VariableDeclaration",+ "scope": 342,+ "src": "173:11:3",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes32",+ "typeString": "bytes32"+ },+ "typeName": {+ "id": 339,+ "name": "bytes32",+ "nodeType": "ElementaryTypeName",+ "src": "173:7:3",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes32",+ "typeString": "bytes32"+ }+ },+ "value": null,+ "visibility": "internal"+ }+ ],+ "src": "159:26:3"+ },+ "src": "152:34:3"+ }+ ],+ "scope": 344,+ "src": "26:163:3"+ }+ ],+ "src": "0:190:3"+ },+ "legacyAST": {+ "absolutePath": "/home/akru/hsweb3test/contracts/Registry.sol",+ "exportedSymbols": {+ "Registry": [+ 343+ ]+ },+ "id": 344,+ "nodeType": "SourceUnit",+ "nodes": [+ {+ "id": 326,+ "literals": [+ "solidity",+ "^",+ "0.4",+ ".22"+ ],+ "nodeType": "PragmaDirective",+ "src": "0:24:3"+ },+ {+ "baseContracts": [],+ "contractDependencies": [],+ "contractKind": "contract",+ "documentation": null,+ "fullyImplemented": true,+ "id": 343,+ "linearizedBaseContracts": [+ 343+ ],+ "name": "Registry",+ "nodeType": "ContractDefinition",+ "nodes": [+ {+ "anonymous": false,+ "documentation": null,+ "id": 330,+ "name": "A",+ "nodeType": "EventDefinition",+ "parameters": {+ "id": 329,+ "nodeType": "ParameterList",+ "parameters": [+ {+ "constant": false,+ "id": 328,+ "indexed": true,+ "name": "listingHash",+ "nodeType": "VariableDeclaration",+ "scope": 330,+ "src": "60:27:3",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes32",+ "typeString": "bytes32"+ },+ "typeName": {+ "id": 327,+ "name": "bytes32",+ "nodeType": "ElementaryTypeName",+ "src": "60:7:3",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes32",+ "typeString": "bytes32"+ }+ },+ "value": null,+ "visibility": "internal"+ }+ ],+ "src": "59:29:3"+ },+ "src": "52:37:3"+ },+ {+ "anonymous": false,+ "documentation": null,+ "id": 336,+ "name": "B",+ "nodeType": "EventDefinition",+ "parameters": {+ "id": 335,+ "nodeType": "ParameterList",+ "parameters": [+ {+ "constant": false,+ "id": 332,+ "indexed": true,+ "name": "sender",+ "nodeType": "VariableDeclaration",+ "scope": 336,+ "src": "102:22:3",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_address",+ "typeString": "address"+ },+ "typeName": {+ "id": 331,+ "name": "address",+ "nodeType": "ElementaryTypeName",+ "src": "102:7:3",+ "typeDescriptions": {+ "typeIdentifier": "t_address",+ "typeString": "address"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 334,+ "indexed": false,+ "name": "listingHash",+ "nodeType": "VariableDeclaration",+ "scope": 336,+ "src": "126:19:3",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes32",+ "typeString": "bytes32"+ },+ "typeName": {+ "id": 333,+ "name": "bytes32",+ "nodeType": "ElementaryTypeName",+ "src": "126:7:3",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes32",+ "typeString": "bytes32"+ }+ },+ "value": null,+ "visibility": "internal"+ }+ ],+ "src": "101:45:3"+ },+ "src": "94:53:3"+ },+ {+ "anonymous": false,+ "documentation": null,+ "id": 342,+ "name": "C",+ "nodeType": "EventDefinition",+ "parameters": {+ "id": 341,+ "nodeType": "ParameterList",+ "parameters": [+ {+ "constant": false,+ "id": 338,+ "indexed": false,+ "name": "dog",+ "nodeType": "VariableDeclaration",+ "scope": 342,+ "src": "160:11:3",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_address",+ "typeString": "address"+ },+ "typeName": {+ "id": 337,+ "name": "address",+ "nodeType": "ElementaryTypeName",+ "src": "160:7:3",+ "typeDescriptions": {+ "typeIdentifier": "t_address",+ "typeString": "address"+ }+ },+ "value": null,+ "visibility": "internal"+ },+ {+ "constant": false,+ "id": 340,+ "indexed": false,+ "name": "cat",+ "nodeType": "VariableDeclaration",+ "scope": 342,+ "src": "173:11:3",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes32",+ "typeString": "bytes32"+ },+ "typeName": {+ "id": 339,+ "name": "bytes32",+ "nodeType": "ElementaryTypeName",+ "src": "173:7:3",+ "typeDescriptions": {+ "typeIdentifier": "t_bytes32",+ "typeString": "bytes32"+ }+ },+ "value": null,+ "visibility": "internal"+ }+ ],+ "src": "159:26:3"+ },+ "src": "152:34:3"+ }+ ],+ "scope": 344,+ "src": "26:163:3"+ }+ ],+ "src": "0:190:3"+ },+ "compiler": {+ "name": "solc",+ "version": "0.4.24+commit.e67f0147.Emscripten.clang"+ },+ "networks": {},+ "schemaVersion": "2.0.1",+ "updatedAt": "2018-10-17T08:27:57.792Z"+}
+ test/contracts/SimpleStorage.json view
@@ -0,0 +1,600 @@+{+ "contractName": "SimpleStorage",+ "abi": [+ {+ "constant": true,+ "inputs": [],+ "name": "count",+ "outputs": [+ {+ "name": "",+ "type": "uint256"+ }+ ],+ "payable": false,+ "stateMutability": "view",+ "type": "function"+ },+ {+ "anonymous": false,+ "inputs": [+ {+ "indexed": false,+ "name": "_count",+ "type": "uint256"+ }+ ],+ "name": "_CountSet",+ "type": "event"+ },+ {+ "constant": false,+ "inputs": [+ {+ "name": "_count",+ "type": "uint256"+ }+ ],+ "name": "setCount",+ "outputs": [],+ "payable": false,+ "stateMutability": "nonpayable",+ "type": "function"+ }+ ],+ "bytecode": "0x608060405234801561001057600080fd5b50610113806100206000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306661abd14604e578063d14e62b8146076575b600080fd5b348015605957600080fd5b50606060a0565b6040518082815260200191505060405180910390f35b348015608157600080fd5b50609e6004803603810190808035906020019092919050505060a6565b005b60005481565b806000819055507f23420683cdbc4b73b0779e0325c497f5b72b3e8a92f3882a5a754c1b9eb734ec816040518082815260200191505060405180910390a1505600a165627a7a72305820a2e06ca2fff9366521c668d197df2b9e7164abd3974f3b0d54e6690ca00798400029",+ "deployedBytecode": "0x6080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306661abd14604e578063d14e62b8146076575b600080fd5b348015605957600080fd5b50606060a0565b6040518082815260200191505060405180910390f35b348015608157600080fd5b50609e6004803603810190808035906020019092919050505060a6565b005b60005481565b806000819055507f23420683cdbc4b73b0779e0325c497f5b72b3e8a92f3882a5a754c1b9eb734ec816040518082815260200191505060405180910390a1505600a165627a7a72305820a2e06ca2fff9366521c668d197df2b9e7164abd3974f3b0d54e6690ca00798400029",+ "sourceMap": "26:201:1:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;26:201:1;;;;;;;",+ "deployedSourceMap": "26:201:1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;55:17;;8:9:-1;5:2;;;30:1;27;20:12;5:2;55:17:1;;;;;;;;;;;;;;;;;;;;;;;122:103;;8:9:-1;5:2;;;30:1;27;20:12;5:2;122:103:1;;;;;;;;;;;;;;;;;;;;;;;;;;55:17;;;;:::o;122:103::-;180:6;172:5;:14;;;;201:17;211:6;201:17;;;;;;;;;;;;;;;;;;122:103;:::o",+ "source": "pragma solidity ^0.4.15;\n\ncontract SimpleStorage {\n uint public count;\n \n event _CountSet(uint _count);\n \n function setCount(uint _count) external {\n count = _count;\n emit _CountSet(_count);\n }\n}\n",+ "sourcePath": "/home/akru/hsweb3test/contracts/SimpleStorage.sol",+ "ast": {+ "absolutePath": "/home/akru/hsweb3test/contracts/SimpleStorage.sol",+ "exportedSymbols": {+ "SimpleStorage": [+ 190+ ]+ },+ "id": 191,+ "nodeType": "SourceUnit",+ "nodes": [+ {+ "id": 169,+ "literals": [+ "solidity",+ "^",+ "0.4",+ ".15"+ ],+ "nodeType": "PragmaDirective",+ "src": "0:24:1"+ },+ {+ "baseContracts": [],+ "contractDependencies": [],+ "contractKind": "contract",+ "documentation": null,+ "fullyImplemented": true,+ "id": 190,+ "linearizedBaseContracts": [+ 190+ ],+ "name": "SimpleStorage",+ "nodeType": "ContractDefinition",+ "nodes": [+ {+ "constant": false,+ "id": 171,+ "name": "count",+ "nodeType": "VariableDeclaration",+ "scope": 190,+ "src": "55:17:1",+ "stateVariable": true,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ },+ "typeName": {+ "id": 170,+ "name": "uint",+ "nodeType": "ElementaryTypeName",+ "src": "55:4:1",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "value": null,+ "visibility": "public"+ },+ {+ "anonymous": false,+ "documentation": null,+ "id": 175,+ "name": "_CountSet",+ "nodeType": "EventDefinition",+ "parameters": {+ "id": 174,+ "nodeType": "ParameterList",+ "parameters": [+ {+ "constant": false,+ "id": 173,+ "indexed": false,+ "name": "_count",+ "nodeType": "VariableDeclaration",+ "scope": 175,+ "src": "99:11:1",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ },+ "typeName": {+ "id": 172,+ "name": "uint",+ "nodeType": "ElementaryTypeName",+ "src": "99:4:1",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "value": null,+ "visibility": "internal"+ }+ ],+ "src": "98:13:1"+ },+ "src": "83:29:1"+ },+ {+ "body": {+ "id": 188,+ "nodeType": "Block",+ "src": "162:63:1",+ "statements": [+ {+ "expression": {+ "argumentTypes": null,+ "id": 182,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "leftHandSide": {+ "argumentTypes": null,+ "id": 180,+ "name": "count",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 171,+ "src": "172:5:1",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "nodeType": "Assignment",+ "operator": "=",+ "rightHandSide": {+ "argumentTypes": null,+ "id": 181,+ "name": "_count",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 177,+ "src": "180:6:1",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "src": "172:14:1",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "id": 183,+ "nodeType": "ExpressionStatement",+ "src": "172:14:1"+ },+ {+ "eventCall": {+ "argumentTypes": null,+ "arguments": [+ {+ "argumentTypes": null,+ "id": 185,+ "name": "_count",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 177,+ "src": "211:6:1",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ }+ ],+ "expression": {+ "argumentTypes": [+ {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ ],+ "id": 184,+ "name": "_CountSet",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 175,+ "src": "201:9:1",+ "typeDescriptions": {+ "typeIdentifier": "t_function_event_nonpayable$_t_uint256_$returns$__$",+ "typeString": "function (uint256)"+ }+ },+ "id": 186,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "functionCall",+ "lValueRequested": false,+ "names": [],+ "nodeType": "FunctionCall",+ "src": "201:17:1",+ "typeDescriptions": {+ "typeIdentifier": "t_tuple$__$",+ "typeString": "tuple()"+ }+ },+ "id": 187,+ "nodeType": "EmitStatement",+ "src": "196:22:1"+ }+ ]+ },+ "documentation": null,+ "id": 189,+ "implemented": true,+ "isConstructor": false,+ "isDeclaredConst": false,+ "modifiers": [],+ "name": "setCount",+ "nodeType": "FunctionDefinition",+ "parameters": {+ "id": 178,+ "nodeType": "ParameterList",+ "parameters": [+ {+ "constant": false,+ "id": 177,+ "name": "_count",+ "nodeType": "VariableDeclaration",+ "scope": 189,+ "src": "140:11:1",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ },+ "typeName": {+ "id": 176,+ "name": "uint",+ "nodeType": "ElementaryTypeName",+ "src": "140:4:1",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "value": null,+ "visibility": "internal"+ }+ ],+ "src": "139:13:1"+ },+ "payable": false,+ "returnParameters": {+ "id": 179,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "162:0:1"+ },+ "scope": 190,+ "src": "122:103:1",+ "stateMutability": "nonpayable",+ "superFunction": null,+ "visibility": "external"+ }+ ],+ "scope": 191,+ "src": "26:201:1"+ }+ ],+ "src": "0:228:1"+ },+ "legacyAST": {+ "absolutePath": "/home/akru/hsweb3test/contracts/SimpleStorage.sol",+ "exportedSymbols": {+ "SimpleStorage": [+ 190+ ]+ },+ "id": 191,+ "nodeType": "SourceUnit",+ "nodes": [+ {+ "id": 169,+ "literals": [+ "solidity",+ "^",+ "0.4",+ ".15"+ ],+ "nodeType": "PragmaDirective",+ "src": "0:24:1"+ },+ {+ "baseContracts": [],+ "contractDependencies": [],+ "contractKind": "contract",+ "documentation": null,+ "fullyImplemented": true,+ "id": 190,+ "linearizedBaseContracts": [+ 190+ ],+ "name": "SimpleStorage",+ "nodeType": "ContractDefinition",+ "nodes": [+ {+ "constant": false,+ "id": 171,+ "name": "count",+ "nodeType": "VariableDeclaration",+ "scope": 190,+ "src": "55:17:1",+ "stateVariable": true,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ },+ "typeName": {+ "id": 170,+ "name": "uint",+ "nodeType": "ElementaryTypeName",+ "src": "55:4:1",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "value": null,+ "visibility": "public"+ },+ {+ "anonymous": false,+ "documentation": null,+ "id": 175,+ "name": "_CountSet",+ "nodeType": "EventDefinition",+ "parameters": {+ "id": 174,+ "nodeType": "ParameterList",+ "parameters": [+ {+ "constant": false,+ "id": 173,+ "indexed": false,+ "name": "_count",+ "nodeType": "VariableDeclaration",+ "scope": 175,+ "src": "99:11:1",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ },+ "typeName": {+ "id": 172,+ "name": "uint",+ "nodeType": "ElementaryTypeName",+ "src": "99:4:1",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "value": null,+ "visibility": "internal"+ }+ ],+ "src": "98:13:1"+ },+ "src": "83:29:1"+ },+ {+ "body": {+ "id": 188,+ "nodeType": "Block",+ "src": "162:63:1",+ "statements": [+ {+ "expression": {+ "argumentTypes": null,+ "id": 182,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "lValueRequested": false,+ "leftHandSide": {+ "argumentTypes": null,+ "id": 180,+ "name": "count",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 171,+ "src": "172:5:1",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "nodeType": "Assignment",+ "operator": "=",+ "rightHandSide": {+ "argumentTypes": null,+ "id": 181,+ "name": "_count",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 177,+ "src": "180:6:1",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "src": "172:14:1",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "id": 183,+ "nodeType": "ExpressionStatement",+ "src": "172:14:1"+ },+ {+ "eventCall": {+ "argumentTypes": null,+ "arguments": [+ {+ "argumentTypes": null,+ "id": 185,+ "name": "_count",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 177,+ "src": "211:6:1",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ }+ ],+ "expression": {+ "argumentTypes": [+ {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ ],+ "id": 184,+ "name": "_CountSet",+ "nodeType": "Identifier",+ "overloadedDeclarations": [],+ "referencedDeclaration": 175,+ "src": "201:9:1",+ "typeDescriptions": {+ "typeIdentifier": "t_function_event_nonpayable$_t_uint256_$returns$__$",+ "typeString": "function (uint256)"+ }+ },+ "id": 186,+ "isConstant": false,+ "isLValue": false,+ "isPure": false,+ "kind": "functionCall",+ "lValueRequested": false,+ "names": [],+ "nodeType": "FunctionCall",+ "src": "201:17:1",+ "typeDescriptions": {+ "typeIdentifier": "t_tuple$__$",+ "typeString": "tuple()"+ }+ },+ "id": 187,+ "nodeType": "EmitStatement",+ "src": "196:22:1"+ }+ ]+ },+ "documentation": null,+ "id": 189,+ "implemented": true,+ "isConstructor": false,+ "isDeclaredConst": false,+ "modifiers": [],+ "name": "setCount",+ "nodeType": "FunctionDefinition",+ "parameters": {+ "id": 178,+ "nodeType": "ParameterList",+ "parameters": [+ {+ "constant": false,+ "id": 177,+ "name": "_count",+ "nodeType": "VariableDeclaration",+ "scope": 189,+ "src": "140:11:1",+ "stateVariable": false,+ "storageLocation": "default",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ },+ "typeName": {+ "id": 176,+ "name": "uint",+ "nodeType": "ElementaryTypeName",+ "src": "140:4:1",+ "typeDescriptions": {+ "typeIdentifier": "t_uint256",+ "typeString": "uint256"+ }+ },+ "value": null,+ "visibility": "internal"+ }+ ],+ "src": "139:13:1"+ },+ "payable": false,+ "returnParameters": {+ "id": 179,+ "nodeType": "ParameterList",+ "parameters": [],+ "src": "162:0:1"+ },+ "scope": 190,+ "src": "122:103:1",+ "stateMutability": "nonpayable",+ "superFunction": null,+ "visibility": "external"+ }+ ],+ "scope": 191,+ "src": "26:201:1"+ }+ ],+ "src": "0:228:1"+ },+ "compiler": {+ "name": "solc",+ "version": "0.4.24+commit.e67f0147.Emscripten.clang"+ },+ "networks": {},+ "schemaVersion": "2.0.1",+ "updatedAt": "2018-10-17T08:28:45.992Z"+}
+ unit/Crypto/Ethereum/Test/EcdsaSpec.hs view
@@ -0,0 +1,32 @@+{-# LANGUAGE OverloadedStrings #-}+module Crypto.Ethereum.Test.EcdsaSpec where++import Crypto.Secp256k1 (SecKey, derivePubKey)+import Data.ByteArray (convert)+import Data.ByteString (ByteString, pack)+import Data.Serialize (decode)+import Test.Hspec+import Test.Hspec.QuickCheck++import Crypto.Ethereum+import Data.ByteArray.HexString (HexString)+import Data.Solidity.Prim.Address (fromPubKey)++spec :: Spec+spec = do+ describe "Ethereum signatures" $ do+ let key = "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20" :: SecKey+ address = fromPubKey (derivePubKey key)+ message = "Hello World!" :: ByteString+ sign = "0xd4a9620cd94387a31b9333935f1e76fbee8467c283d07c39c1606dc4e2af021e317293af09601dbb48f547e40f6b98fe8a67a23dcd1f7f8d054695a81521177001" :: HexString+ sign' = either error id $ decode (convert sign)++ it "sign message by Ethereum private key" $ do+ ecsign key message `shouldBe` sign'++ it "verify message by Ethereum public key" $ do+ ecrecover sign' message `shouldBe` Just address++ prop "round robin sign/verify for random message" $ \chars ->+ let msg = pack chars+ in ecrecover (ecsign key msg) msg `shouldBe` Just address
+ unit/Data/Solidity/Test/AddressSpec.hs view
@@ -0,0 +1,62 @@+{-# LANGUAGE OverloadedStrings #-}+module Data.Solidity.Test.AddressSpec where++import Crypto.Secp256k1 (SecKey, derivePubKey)+import Data.ByteString (ByteString)+import Data.ByteString.Char8 (unpack)+import Data.Foldable (for_)+import Data.Monoid ((<>))+import Test.Hspec++import Data.Solidity.Prim.Address++spec :: Spec+spec = do+ describe "EIP55 Test Vectors" $ for_ checksummedAddrs (\addr ->+ it (unpack addr <> " should be checksummed") $ verifyChecksum addr `shouldBe` True)++ describe "EIP55 Test Vectors Tampered" $ for_ unchecksummedAddrs (\addr ->+ it (unpack addr <> " should not be checksummed") $ verifyChecksum addr `shouldBe` False)++ describe "Conversion from/to hex string" $ do+ it "should convert from/to on valid hex" $ do+ fromHexString "0x6370eF2f4Db3611D657b90667De398a2Cc2a370C"+ `shouldBe` Right "0x6370eF2f4Db3611D657b90667De398a2Cc2a370C"++ toHexString "0x6370eF2f4Db3611D657b90667De398a2Cc2a370C"+ `shouldBe` "0x6370eF2f4Db3611D657b90667De398a2Cc2a370C"++ it "should fail on broken hex" $ do+ fromHexString "0x42"+ `shouldBe` Left "Incorrect address length: 1"+++ describe "Conversion from Secp256k1 keys" $ do+ it "derivation from private key" $ do+ let key = "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20" :: SecKey+ fromPubKey (derivePubKey key)+ `shouldBe` "0x6370eF2f4Db3611D657b90667De398a2Cc2a370C"++checksummedAddrs :: [ByteString]+checksummedAddrs =+ [ "0x52908400098527886E0F7030069857D2E4169EE7"+ , "0x8617E340B3D01FA5F11F306F4090FD50E238070D"+ , "0xde709f2102306220921060314715629080e2fb77"+ , "0x27b1fdb04752bbc536007a920d24acb045561c26"+ , "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"+ , "0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359"+ , "0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB"+ , "0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb"+ ]++unchecksummedAddrs :: [ByteString]+unchecksummedAddrs =+ [ "0x52908400098527886E0F7030069857D2E4169Ee7"+ , "0x8617E340B3D01FA5F11F306F4090FD50E238070d"+ , "0xde709f2102306220921060314715629080e2fB77"+ , "0x27b1fdb04752bbc536007a920d24acb045561C26"+ , "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAeD"+ , "0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5D359"+ , "0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6Fb"+ , "0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDB"+ ]
+ unit/Data/Solidity/Test/EncodingSpec.hs view
@@ -0,0 +1,265 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedLists #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeFamilies #-}++module Data.Solidity.Test.EncodingSpec where++import Control.Exception (evaluate)+import Data.Monoid ((<>))+import Data.Text (Text)+import Data.Tuple.OneTuple (OneTuple (..))+import Generics.SOP (Generic, Rep)+import Test.Hspec++import Data.Solidity.Abi (AbiGet, AbiPut, GenericAbiGet,+ GenericAbiPut)+import Data.Solidity.Abi.Codec (decode, decode', encode, encode')+import Data.Solidity.Prim (Address, Bytes, BytesN, IntN,+ ListN, UIntN)+import Data.Solidity.Prim.Address (fromHexString, toHexString)++spec :: Spec+spec = do+ intNTest+ bytesTest+ bytesNTest+ vectorTest+ dynamicArraysTest+ tuplesTest+ addressTest++intNTest :: Spec+intNTest =+ describe "uint tests" $ do++ it "can encode int16" $+ let decoded = (-1) :: IntN 16+ encoded = "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"+ in roundTrip decoded encoded++ it "can encode larger uint256" $+ let decoded = (2 ^ 255) - 1 :: UIntN 256+ encoded = "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"+ in roundTrip decoded encoded++bytesTest :: Spec+bytesTest = do+ describe "bytes tests" $ do++ it "can encode empty bytes" $ do+ let decoded :: Bytes+ decoded = "0x"+ encoded = "0x0000000000000000000000000000000000000000000000000000000000000000"+ in roundTrip decoded encoded++ it "can encode short bytes" $ do+ let decoded :: Bytes+ decoded = "0xc3a40000c3a4"+ encoded = "0x0000000000000000000000000000000000000000000000000000000000000006"+ <> "0xc3a40000c3a40000000000000000000000000000000000000000000000000000"+ in roundTrip decoded encoded++ it "can encode long bytes" $ do+ let decoded :: Bytes+ decoded = "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"+ <> "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"+ <> "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"+ <> "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"+ <> "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1"+ encoded = "0x000000000000000000000000000000000000000000000000000000000000009f"+ <> "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"+ <> "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"+ <> "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"+ <> "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"+ <> "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff100"+ in roundTrip decoded encoded++bytesNTest :: Spec+bytesNTest =+ describe "sized bytes tests" $ do++ it "can encode Bytes1" $ do+ let decoded = "0xcf" :: BytesN 1+ encoded = "0xcf00000000000000000000000000000000000000000000000000000000000000"+ roundTrip decoded encoded++ it "can encode Bytes12" $ do+ let decoded = "0x6761766f66796f726b000000" :: BytesN 12+ encoded = "0x6761766f66796f726b0000000000000000000000000000000000000000000000"+ roundTrip decoded encoded++ it "can pad shorter hex-literals" $ do+ let literal = "0xc3a4" :: BytesN 4+ expected = "0xc3a40000" :: BytesN 4+ literal `shouldBe` expected++ it "can pad shorter string-literals" $ do+ let literal = "hello" :: BytesN 8+ expected = "0x68656c6c6f000000" :: BytesN 8+ literal `shouldBe` expected++ it "fails on too long literals" $ do+ let literal = "hello" :: BytesN 4+ evaluate literal `shouldThrow` errorCall "Invalid Size"++vectorTest :: Spec+vectorTest =+ describe "statically sized array tests" $ do++ it "can encode statically sized vectors of addresses" $ do+ let decoded = [False, True] :: ListN 2 Bool+ encoded = "0x0000000000000000000000000000000000000000000000000000000000000000"+ <> "0x0000000000000000000000000000000000000000000000000000000000000001"+ in roundTrip decoded encoded++ it "can encode statically sized vectors of statically sized bytes"$ do+ let elem1 = "0xcf"+ elem2 = "0x68"+ elem3 = "0x4d"+ elem4 = "0xfb"+ decoded = [elem1, elem2, elem3, elem4] :: ListN 4 (BytesN 1)+ encoded = "0xcf00000000000000000000000000000000000000000000000000000000000000"+ <> "0x6800000000000000000000000000000000000000000000000000000000000000"+ <> "0x4d00000000000000000000000000000000000000000000000000000000000000"+ <> "0xfb00000000000000000000000000000000000000000000000000000000000000"+ in roundTrip decoded encoded++dynamicArraysTest :: Spec+dynamicArraysTest = do+ describe "dynamically sized array tests" $ do++ it "can encode dynamically sized lists of bools" $ do+ let decoded = [True, True, False] :: [Bool]+ encoded = "0x0000000000000000000000000000000000000000000000000000000000000003"+ <> "0x0000000000000000000000000000000000000000000000000000000000000001"+ <> "0x0000000000000000000000000000000000000000000000000000000000000001"+ <> "0x0000000000000000000000000000000000000000000000000000000000000000"+ in roundTrip decoded encoded++tuplesTest :: Spec+tuplesTest =+ describe "tuples test" $ do++ it "can encode 2-tuples with both static args" $ do+ let decoded = (True, False)+ encoded = "0x0000000000000000000000000000000000000000000000000000000000000001"+ <> "0x0000000000000000000000000000000000000000000000000000000000000000"+ in roundTripGeneric decoded encoded++ it "can encode 1-tuples with dynamic arg" $ do+ let decoded = OneTuple ([True, False] :: [Bool])+ encoded = "0x0000000000000000000000000000000000000000000000000000000000000020"+ <> "0x0000000000000000000000000000000000000000000000000000000000000002"+ <> "0x0000000000000000000000000000000000000000000000000000000000000001"+ <> "0x0000000000000000000000000000000000000000000000000000000000000000"+ in roundTripGeneric decoded encoded++ it "can encode 4-tuples with a mix of args - (UInt32, String, Boolean, Array Int256)" $ do+ let decoded = (1 :: IntN 32, "dave" :: Text, True, [1, 2, 3] :: [IntN 256])+ encoded = "0x0000000000000000000000000000000000000000000000000000000000000001"+ <> "0x0000000000000000000000000000000000000000000000000000000000000080"+ <> "0x0000000000000000000000000000000000000000000000000000000000000001"+ <> "0x00000000000000000000000000000000000000000000000000000000000000c0"+ <> "0x0000000000000000000000000000000000000000000000000000000000000004"+ <> "0x6461766500000000000000000000000000000000000000000000000000000000"+ <> "0x0000000000000000000000000000000000000000000000000000000000000003"+ <> "0x0000000000000000000000000000000000000000000000000000000000000001"+ <> "0x0000000000000000000000000000000000000000000000000000000000000002"+ <> "0x0000000000000000000000000000000000000000000000000000000000000003"+ in roundTripGeneric decoded encoded++ it "can do something really complicated" $ do+ let uint = 1 :: UIntN 256+ int = (-1) :: IntN 256+ bool = True+ int224 = 221 :: IntN 224+ bools = [True, False] :: ListN 2 Bool+ ints = [1, -1, 3] :: [IntN 32]+ string = "hello" :: Text+ bytes16 = "0x12345678123456781234567812345678" :: BytesN 16+ elem1 = "0x1234" :: BytesN 2+ bytes2s = [ [elem1, elem1, elem1, elem1]+ , [elem1, elem1, elem1, elem1]+ ] :: [ListN 4 (BytesN 2)]++ decoded = (uint, int, bool, int224, bools, ints, string, bytes16, bytes2s)++ encoded = "0x0000000000000000000000000000000000000000000000000000000000000001"+ <> "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"+ <> "0x0000000000000000000000000000000000000000000000000000000000000001"+ <> "0x00000000000000000000000000000000000000000000000000000000000000dd"+ <> "0x0000000000000000000000000000000000000000000000000000000000000001"+ <> "0x0000000000000000000000000000000000000000000000000000000000000000"+ <> "0x0000000000000000000000000000000000000000000000000000000000000140"+ <> "0x00000000000000000000000000000000000000000000000000000000000001c0"+ <> "0x1234567812345678123456781234567800000000000000000000000000000000"+ <> "0x0000000000000000000000000000000000000000000000000000000000000200"+ <> "0x0000000000000000000000000000000000000000000000000000000000000003"+ <> "0x0000000000000000000000000000000000000000000000000000000000000001"+ <> "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"+ <> "0x0000000000000000000000000000000000000000000000000000000000000003"+ <> "0x0000000000000000000000000000000000000000000000000000000000000005"+ <> "0x68656c6c6f000000000000000000000000000000000000000000000000000000"+ <> "0x0000000000000000000000000000000000000000000000000000000000000002"+ <> "0x1234000000000000000000000000000000000000000000000000000000000000"+ <> "0x1234000000000000000000000000000000000000000000000000000000000000"+ <> "0x1234000000000000000000000000000000000000000000000000000000000000"+ <> "0x1234000000000000000000000000000000000000000000000000000000000000"+ <> "0x1234000000000000000000000000000000000000000000000000000000000000"+ <> "0x1234000000000000000000000000000000000000000000000000000000000000"+ <> "0x1234000000000000000000000000000000000000000000000000000000000000"+ <> "0x1234000000000000000000000000000000000000000000000000000000000000"++ in roundTripGeneric decoded encoded++addressTest :: Spec+addressTest =+ describe "address test" $ do+ it "can abi encode address" $ do+ let decoded = "0x4af013AfBAdb22D8A88c92D68Fc96B033b9Ebb8a" :: Address+ encoded = "0x0000000000000000000000004af013AfBAdb22D8A88c92D68Fc96B033b9Ebb8a"+ in roundTrip decoded encoded++ it "can decode address from/to bytestring" $ do+ fromHexString "0x4af013AfBAdb22D8A88c92D68Fc96B033b9Ebb8a"+ `shouldBe` Right ("0x4af013AfBAdb22D8A88c92D68Fc96B033b9Ebb8a" :: Address)++ toHexString "0x4af013AfBAdb22D8A88c92D68Fc96B033b9Ebb8a"+ `shouldBe` "0x4af013afbadb22d8a88c92d68fc96b033b9ebb8a"++ it "fails for invalid address length" $ do+ evaluate (fromHexString "0x0")+ `shouldThrow` errorCall "base16: input: invalid length"++ fromHexString "0x4af013AfBAdb22D8A88c92D68Fc96B033b9Ebb8a00"+ `shouldBe` Left "Incorrect address length: 21"++-- | Run encoded/decoded comaration+roundTrip :: ( Show a+ , Eq a+ , AbiPut a+ , AbiGet a+ )+ => a+ -> Bytes+ -> IO ()+roundTrip decoded encoded = do+ encoded `shouldBe` encode decoded+ decode encoded `shouldBe` Right decoded++-- | Run generic encoded/decoded comaration+roundTripGeneric :: ( Show a+ , Eq a+ , Generic a+ , Rep a ~ rep+ , GenericAbiPut rep+ , GenericAbiGet rep+ )+ => a+ -> Bytes+ -> IO ()+roundTripGeneric decoded encoded = do+ encoded `shouldBe` encode' decoded+ decode' encoded `shouldBe` Right decoded
+ unit/Data/Solidity/Test/IntSpec.hs view
@@ -0,0 +1,33 @@+{-# LANGUAGE DataKinds #-}+module Data.Solidity.Test.IntSpec where++import Test.Hspec++import Data.Solidity.Prim.Int++spec :: Spec+spec = do+ describe "Unsigned integer overflow" $ do+ it "UIntN 256" $ do+ (negate 1 :: UIntN 256) `shouldBe` 115792089237316195423570985008687907853269984665640564039457584007913129639935+ (maxBound + 1 :: UIntN 256) `shouldBe` 0++ it "UIntN 128" $ do+ (negate 1 :: UIntN 128) `shouldBe` 340282366920938463463374607431768211455+ (maxBound + 1 :: UIntN 128) `shouldBe` 0++ it "UIntN 64" $ do+ (negate 1 :: UIntN 64) `shouldBe` 18446744073709551615+ (maxBound + 1 :: UIntN 64) `shouldBe` 0++ it "UIntN 32" $ do+ (negate 1 :: UIntN 32) `shouldBe` 4294967295+ (maxBound + 1 :: UIntN 32) `shouldBe` 0++ it "UIntN 16" $ do+ (negate 1 :: UIntN 16) `shouldBe` 65535+ (maxBound + 1 :: UIntN 16) `shouldBe` 0++ it "UIntN 8" $ do+ (negate 1 :: UIntN 8) `shouldBe` 255+ (maxBound + 1 :: UIntN 8) `shouldBe` 0
+ unit/Language/Solidity/Test/CompilerSpec.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE OverloadedLists #-}+{-# LANGUAGE OverloadedStrings #-}++module Language.Solidity.Test.CompilerSpec where++import Language.Solidity.Compiler+import Test.Hspec++spec :: Spec+spec = describe "solidity" $ do+ it "can compile empty contract" $ do+ compile (Sources [("A", "contract A {}")] [] True)+ `shouldBe` Right [("A", ("[]\n", "6080604052348015600f57600080fd5b50603580601d6000396000f3006080604052600080fd00a165627a7a72305820613b8f0a4aab50fea86c1e4943bcddad6d753778395309a4e055efcda614b0690029"))]++ it "can handle broken contract" $ do+ compile (Sources [("Fail", "contract Fail {")] [] True)+ `shouldBe` Left "Fail:1:16: Error: Function, variable, struct or modifier declaration expected.\ncontract Fail {\n ^\n"++ it "can compile simple contract" $ do+ compile (Sources [("SimpleStorage", "contract SimpleStorage { uint256 public a; function set(uint256 _a) { a = _a; } }")] [] True)+ `shouldBe` Right [("SimpleStorage", ("[\n\t{\n\t\t\"constant\" : true,\n\t\t\"inputs\" : [],\n\t\t\"name\" : \"a\",\n\t\t\"outputs\" : \n\t\t[\n\t\t\t{\n\t\t\t\t\"name\" : \"\",\n\t\t\t\t\"type\" : \"uint256\"\n\t\t\t}\n\t\t],\n\t\t\"payable\" : false,\n\t\t\"stateMutability\" : \"view\",\n\t\t\"type\" : \"function\"\n\t},\n\t{\n\t\t\"constant\" : false,\n\t\t\"inputs\" : \n\t\t[\n\t\t\t{\n\t\t\t\t\"name\" : \"_a\",\n\t\t\t\t\"type\" : \"uint256\"\n\t\t\t}\n\t\t],\n\t\t\"name\" : \"set\",\n\t\t\"outputs\" : [],\n\t\t\"payable\" : false,\n\t\t\"stateMutability\" : \"nonpayable\",\n\t\t\"type\" : \"function\"\n\t}\n]\n", "608060405234801561001057600080fd5b5060dc8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630dbe671f14604e57806360fe47b1146076575b600080fd5b348015605957600080fd5b50606060a0565b6040518082815260200191505060405180910390f35b348015608157600080fd5b50609e6004803603810190808035906020019092919050505060a6565b005b60005481565b80600081905550505600a165627a7a7230582053764f3cc73b0960abb0d97899a8133bee5eb98c131978821f7add85f33d4f2e0029"))]
− unit/Network/Ethereum/Web3/Test/EncodingSpec.hs
@@ -1,224 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE OverloadedLists #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TypeFamilies #-}--module Network.Ethereum.Web3.Test.EncodingSpec where--import Data.Monoid ((<>))-import Data.Text (Text)-import Generics.SOP (Generic, Rep)-import Test.Hspec--import Network.Ethereum.ABI.Class (ABIGet, ABIPut,- GenericABIGet, GenericABIPut)-import Network.Ethereum.ABI.Codec (decode, decode', encode,- encode')-import Network.Ethereum.ABI.Prim.Bool ()-import Network.Ethereum.ABI.Prim.Bytes (Bytes, BytesN)-import Network.Ethereum.ABI.Prim.Int (IntN, UIntN)-import Network.Ethereum.ABI.Prim.List (ListN)-import Network.Ethereum.ABI.Prim.String ()-import Network.Ethereum.ABI.Prim.Tuple (Singleton (..))--spec :: Spec-spec = do- intNTest- bytesTest- bytesNTest- vectorTest- dynamicArraysTest- tuplesTest--intNTest :: Spec-intNTest =- describe "uint tests" $ do-- it "can encode int16" $- let decoded = (-1) :: IntN 16- encoded = "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"- in roundTrip decoded encoded-- it "can encode larger uint256" $- let decoded = (2 ^ 255) - 1 :: UIntN 256- encoded = "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"- in roundTrip decoded encoded--bytesTest :: Spec-bytesTest = do- describe "bytes tests" $ do-- it "can encode short bytes" $ do- let decoded :: Bytes- decoded = "0xc3a40000c3a4"- encoded = "0x0000000000000000000000000000000000000000000000000000000000000006"- <> "0xc3a40000c3a40000000000000000000000000000000000000000000000000000"- in roundTrip decoded encoded-- it "can encode long bytes" $ do- let decoded :: Bytes- decoded = "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"- <> "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"- <> "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"- <> "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"- <> "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1"- encoded = "0x000000000000000000000000000000000000000000000000000000000000009f"- <> "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"- <> "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"- <> "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"- <> "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"- <> "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff100"- in roundTrip decoded encoded--bytesNTest :: Spec-bytesNTest =- describe "sized bytes tests" $ do-- it "can encode Bytes1" $ do- let decoded = "0xcf" :: BytesN 1- encoded = "0xcf00000000000000000000000000000000000000000000000000000000000000"- roundTrip decoded encoded-- it "can encode Bytes12" $ do- let decoded = "0x6761766f66796f726b000000" :: BytesN 12- encoded = "0x6761766f66796f726b0000000000000000000000000000000000000000000000"- roundTrip decoded encoded--vectorTest :: Spec-vectorTest =- describe "statically sized array tests" $ do-- it "can encode statically sized vectors of addresses" $ do- let decoded = [False, True] :: ListN 2 Bool- encoded = "0x0000000000000000000000000000000000000000000000000000000000000000"- <> "0x0000000000000000000000000000000000000000000000000000000000000001"- in roundTrip decoded encoded-- it "can encode statically sized vectors of statically sized bytes"$ do- let elem1 = "0xcf"- elem2 = "0x68"- elem3 = "0x4d"- elem4 = "0xfb"- decoded = [elem1, elem2, elem3, elem4] :: ListN 4 (BytesN 1)- encoded = "0xcf00000000000000000000000000000000000000000000000000000000000000"- <> "0x6800000000000000000000000000000000000000000000000000000000000000"- <> "0x4d00000000000000000000000000000000000000000000000000000000000000"- <> "0xfb00000000000000000000000000000000000000000000000000000000000000"- in roundTrip decoded encoded--dynamicArraysTest :: Spec-dynamicArraysTest = do- describe "dynamically sized array tests" $ do-- it "can encode dynamically sized lists of bools" $ do- let decoded = [True, True, False] :: [Bool]- encoded = "0x0000000000000000000000000000000000000000000000000000000000000003"- <> "0x0000000000000000000000000000000000000000000000000000000000000001"- <> "0x0000000000000000000000000000000000000000000000000000000000000001"- <> "0x0000000000000000000000000000000000000000000000000000000000000000"- in roundTrip decoded encoded--tuplesTest :: Spec-tuplesTest =- describe "tuples test" $ do-- it "can encode 2-tuples with both static args" $ do- let decoded = (True, False)- encoded = "0x0000000000000000000000000000000000000000000000000000000000000001"- <> "0x0000000000000000000000000000000000000000000000000000000000000000"- in roundTripGeneric decoded encoded-- it "can encode 1-tuples with dynamic arg" $ do- let decoded = Singleton ([True, False] :: [Bool])- encoded = "0x0000000000000000000000000000000000000000000000000000000000000020"- <> "0x0000000000000000000000000000000000000000000000000000000000000002"- <> "0x0000000000000000000000000000000000000000000000000000000000000001"- <> "0x0000000000000000000000000000000000000000000000000000000000000000"- in roundTripGeneric decoded encoded-- it "can encode 4-tuples with a mix of args - (UInt32, String, Boolean, Array Int256)" $ do- let decoded = (1 :: IntN 32, "dave" :: Text, True, [1, 2, 3] :: [IntN 256])- encoded = "0x0000000000000000000000000000000000000000000000000000000000000001"- <> "0x0000000000000000000000000000000000000000000000000000000000000080"- <> "0x0000000000000000000000000000000000000000000000000000000000000001"- <> "0x00000000000000000000000000000000000000000000000000000000000000c0"- <> "0x0000000000000000000000000000000000000000000000000000000000000004"- <> "0x6461766500000000000000000000000000000000000000000000000000000000"- <> "0x0000000000000000000000000000000000000000000000000000000000000003"- <> "0x0000000000000000000000000000000000000000000000000000000000000001"- <> "0x0000000000000000000000000000000000000000000000000000000000000002"- <> "0x0000000000000000000000000000000000000000000000000000000000000003"- in roundTripGeneric decoded encoded-- it "can do something really complicated" $ do- let uint = 1 :: UIntN 256- int = (-1) :: IntN 256- bool = True- int224 = 221 :: IntN 224- bools = [True, False] :: ListN 2 Bool- ints = [1, (-1), 3] :: [IntN 32]- string = "hello" :: Text- bytes16 = "0x12345678123456781234567812345678" :: BytesN 16- elem = "0x1234" :: BytesN 2- bytes2s = [ [elem, elem, elem, elem]- , [elem, elem, elem, elem]- ] :: [ListN 4 (BytesN 2)]-- decoded = (uint, int, bool, int224, bools, ints, string, bytes16, bytes2s)-- encoded = "0x0000000000000000000000000000000000000000000000000000000000000001"- <> "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"- <> "0x0000000000000000000000000000000000000000000000000000000000000001"- <> "0x00000000000000000000000000000000000000000000000000000000000000dd"- <> "0x0000000000000000000000000000000000000000000000000000000000000001"- <> "0x0000000000000000000000000000000000000000000000000000000000000000"- <> "0x0000000000000000000000000000000000000000000000000000000000000140"- <> "0x00000000000000000000000000000000000000000000000000000000000001c0"- <> "0x1234567812345678123456781234567800000000000000000000000000000000"- <> "0x0000000000000000000000000000000000000000000000000000000000000200"- <> "0x0000000000000000000000000000000000000000000000000000000000000003"- <> "0x0000000000000000000000000000000000000000000000000000000000000001"- <> "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"- <> "0x0000000000000000000000000000000000000000000000000000000000000003"- <> "0x0000000000000000000000000000000000000000000000000000000000000005"- <> "0x68656c6c6f000000000000000000000000000000000000000000000000000000"- <> "0x0000000000000000000000000000000000000000000000000000000000000002"- <> "0x1234000000000000000000000000000000000000000000000000000000000000"- <> "0x1234000000000000000000000000000000000000000000000000000000000000"- <> "0x1234000000000000000000000000000000000000000000000000000000000000"- <> "0x1234000000000000000000000000000000000000000000000000000000000000"- <> "0x1234000000000000000000000000000000000000000000000000000000000000"- <> "0x1234000000000000000000000000000000000000000000000000000000000000"- <> "0x1234000000000000000000000000000000000000000000000000000000000000"- <> "0x1234000000000000000000000000000000000000000000000000000000000000"-- in roundTripGeneric decoded encoded---- | Run encoded/decoded comaration-roundTrip :: ( Show a- , Eq a- , ABIPut a- , ABIGet a- )- => a- -> Bytes- -> IO ()-roundTrip decoded encoded = do- encoded `shouldBe` encode decoded- decode encoded `shouldBe` Right decoded---- | Run generic encoded/decoded comaration-roundTripGeneric :: ( Show a- , Eq a- , Generic a- , Rep a ~ rep- , GenericABIPut rep- , GenericABIGet rep- )- => a- -> Bytes- -> IO ()-roundTripGeneric decoded encoded = do- encoded `shouldBe` encode' decoded- decode' encoded `shouldBe` Right decoded
unit/Network/Ethereum/Web3/Test/EventSpec.hs view
@@ -5,20 +5,15 @@ module Network.Ethereum.Web3.Test.EventSpec where -import Data.Tagged (Tagged)-import Generics.SOP (Generic)-import qualified GHC.Generics as GHC (Generic)-import Test.Hspec (Spec, describe, it,- shouldBe)+import Data.Tagged (Tagged)+import Generics.SOP (Generic)+import qualified GHC.Generics as GHC (Generic)+import Test.Hspec (Spec, describe, it, shouldBe) -import Network.Ethereum.ABI.Class (ABIGet)-import Network.Ethereum.ABI.Event (IndexedEvent (..),- decodeEvent)-import Network.Ethereum.ABI.Prim.Address (Address)-import Network.Ethereum.ABI.Prim.Bytes ()-import Network.Ethereum.ABI.Prim.Int (UIntN)-import Network.Ethereum.ABI.Prim.Tagged ()-import Network.Ethereum.Web3.Types (Change (..))+import Data.Solidity.Abi (AbiGet, AbiType (..))+import Data.Solidity.Event (IndexedEvent (..), decodeEvent)+import Data.Solidity.Prim (Address, UIntN)+import Network.Ethereum.Api.Types (Change (..)) spec :: Spec@@ -60,11 +55,18 @@ data NewCount = NewCount (UIntN 256) deriving (Eq, Show, GHC.Generic) instance Generic NewCount + data NewCountIndexed = NewCountIndexed deriving (Eq, Show, GHC.Generic) instance Generic NewCountIndexed+instance AbiType NewCountIndexed where+ isDynamic = const False+instance AbiGet NewCountIndexed data NewCountNonIndexed = NewCountNonIndexed (Tagged 1 (UIntN 256)) deriving (Eq, Show, GHC.Generic) instance Generic NewCountNonIndexed+instance AbiType NewCountNonIndexed where+ isDynamic = const False+instance AbiGet NewCountNonIndexed instance IndexedEvent NewCountIndexed NewCountNonIndexed NewCount where isAnonymous = const False@@ -75,9 +77,15 @@ data TransferIndexed = TransferIndexed (Tagged 1 Address) (Tagged 3 Address) deriving (Eq, Show, GHC.Generic) instance Generic TransferIndexed+instance AbiType TransferIndexed where+ isDynamic = const False+instance AbiGet TransferIndexed data TransferNonIndexed = TransferNonIndexed (Tagged 2 (UIntN 256)) deriving (Eq, Show, GHC.Generic) instance Generic TransferNonIndexed+instance AbiType TransferNonIndexed where+ isDynamic = const False+instance AbiGet TransferNonIndexed instance IndexedEvent TransferIndexed TransferNonIndexed Transfer where isAnonymous = const False
+ unit/Network/Ethereum/Web3/Test/LocalAccountSpec.hs view
@@ -0,0 +1,26 @@+{-# LANGUAGE OverloadedStrings #-}++module Network.Ethereum.Web3.Test.LocalAccountSpec where++import Crypto.Ethereum (SecKey)+import Test.Hspec++import Network.Ethereum.Account.PrivateKey (signTransaction)+import Network.Ethereum.Api.Types (Call (..), Quantity (..))++-- using same example as in this blog post:+-- https://medium.com/@codetractio/walkthrough-of-an-ethereum-improvement-proposal-eip-6fda3966d171+spec :: Spec+spec = describe "transaction signing" $ do+ let testCall = Call Nothing+ (Just "0x3535353535353535353535353535353535353535")+ (Just . Quantity $ 21000)+ (Just . Quantity $ 20000000000)+ (Just . Quantity $ 1000000000000000000)+ Nothing+ (Just 9)+ privKey = "4646464646464646464646464646464646464646464646464646464646464646" :: SecKey+ correctSignedTx = "0xf86c098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a76400008025a028ef61340bd939bc2195fe537567866003e1a15d3c71ff63e1590620aa636276a067cbe9d8997f761aecb703304b3800ccf555c9f3dc64214b297fb1966a3b6d83"++ it "can create valid raw transaction" $+ signTransaction testCall 1 privKey `shouldBe` correctSignedTx
unit/Network/Ethereum/Web3/Test/MethodDumpSpec.hs view
@@ -4,11 +4,10 @@ import Network.Ethereum.Contract.TH import Test.Hspec-import Text.Printf spec :: Spec spec = describe "methodDump" $ it "can dump an ABI" $ do- let theApiDump = [abiFrom|examples/ERC20.json|]+ let theApiDump = [abiFrom|examples/token/ERC20.json|] in theApiDump `shouldNotBe` ""
web3.cabal view
@@ -1,12 +1,13 @@-cabal-version: >=1.10+cabal-version: 1.12 name: web3-version: 0.7.3.0+version: 0.8.0.0 license: BSD3 license-file: LICENSE-copyright: Alexander Krupenkin+copyright: (c) Alexander Krupenkin 2016 maintainer: mail@akru.me author: Alexander Krupenkin homepage: https://github.com/airalab/hs-web3#readme+bug-reports: https://github.com/airalab/hs-web3/issues synopsis: Ethereum API for Haskell description: Web3 is a Haskell client library for Ethereum@@ -15,147 +16,253 @@ extra-source-files: README.md CHANGELOG.md- test-support/contracts/Migrations.sol- test-support/contracts/SimpleStorage.sol- test-support/truffle.js- test-support/migrations/1_initial_migration.js- test-support/migrations/2_deploy_contracts.js- test-support/convertAbi.sh- test-support/inject-contract-addresses.sh- examples/ERC20.hs- examples/ERC20.json- examples/TokenInfo.hs+ stack.yaml+ examples/token/ERC20.hs+ examples/token/ERC20.json+ examples/token/Main.hs+ test/contracts/Registry.json+ test/contracts/SimpleStorage.json+ test/contracts/ComplexStorage.json+ test/contracts/Linearization.json source-repository head type: git location: https://github.com/airalab/hs-web3 -flag tls+flag debug description:- Enable TLS support+ Enable debug compiler options default: False+ manual: True +flag solidity+ description:+ Enable Solidity compiler+ default: False+ manual: True+ library exposed-modules:- Network.Ethereum.Web3- Network.Ethereum.Web3.Eth- Network.Ethereum.Web3.Net- Network.Ethereum.Web3.Web3- Network.Ethereum.Web3.Types- Network.Ethereum.Web3.Provider- Network.Ethereum.Unit- Network.Ethereum.ABI.Json- Network.Ethereum.ABI.Class- Network.Ethereum.ABI.Codec- Network.Ethereum.ABI.Event- Network.Ethereum.ABI.Event.Internal- Network.Ethereum.ABI.Generic- Network.Ethereum.ABI.Prim- Network.Ethereum.ABI.Prim.Int- Network.Ethereum.ABI.Prim.Bool- Network.Ethereum.ABI.Prim.List- Network.Ethereum.ABI.Prim.Bytes- Network.Ethereum.ABI.Prim.Tuple- Network.Ethereum.ABI.Prim.Tuple.TH- Network.Ethereum.ABI.Prim.String- Network.Ethereum.ABI.Prim.Tagged- Network.Ethereum.ABI.Prim.Address- Network.Ethereum.Contract.TH+ Crypto.Ethereum+ Data.ByteArray.HexString+ Data.Solidity.Abi+ Data.Solidity.Abi.Codec+ Data.Solidity.Abi.Generic+ Data.Solidity.Event+ Data.Solidity.Event.Internal+ Data.Solidity.Prim+ Data.Solidity.Prim.Address+ Data.Solidity.Prim.Bool+ Data.Solidity.Prim.Bytes+ Data.Solidity.Prim.Int+ Data.Solidity.Prim.List+ Data.Solidity.Prim.String+ Data.Solidity.Prim.Tagged+ Data.Solidity.Prim.Tuple+ Data.Solidity.Prim.Tuple.TH+ Data.String.Extra+ Language.Solidity.Abi+ Language.Solidity.Compiler+ Language.Solidity.Compiler.Foreign+ Network.Ethereum.Account+ Network.Ethereum.Account.Class+ Network.Ethereum.Account.Default+ Network.Ethereum.Account.Internal+ Network.Ethereum.Account.Personal+ Network.Ethereum.Account.PrivateKey+ Network.Ethereum.Account.Safe+ Network.Ethereum.Api.Eth+ Network.Ethereum.Api.Net+ Network.Ethereum.Api.Personal+ Network.Ethereum.Api.Provider+ Network.Ethereum.Api.Types+ Network.Ethereum.Api.Web3+ Network.Ethereum.Chain+ Network.Ethereum.Contract Network.Ethereum.Contract.Event+ Network.Ethereum.Contract.Event.Common+ Network.Ethereum.Contract.Event.MultiFilter+ Network.Ethereum.Contract.Event.SingleFilter Network.Ethereum.Contract.Method+ Network.Ethereum.Contract.TH+ Network.Ethereum.Ens+ Network.Ethereum.Ens.PublicResolver+ Network.Ethereum.Ens.Registry+ Network.Ethereum.Unit+ Network.Ethereum.Web3 Network.JsonRpc.TinyClient- Data.String.Extra hs-source-dirs: src+ other-modules:+ Paths_web3 default-language: Haskell2010- ghc-options: -Wduplicate-exports -Whi-shadowing -Widentities- -Wnoncanonical-monoid-instances -Woverlapping-patterns -Wtabs- -Wpartial-type-signatures -Wderiving-typeable- -Wunrecognised-pragmas -Wunticked-promoted-constructors- -Wtyped-holes -Wincomplete-patterns -Wincomplete-uni-patterns- -Wmissing-fields -Wmissing-methods -Wmissing-exported-signatures+ ghc-options: -funbox-strict-fields -Wduplicate-exports+ -Whi-shadowing -Widentities -Woverlapping-patterns+ -Wpartial-type-signatures -Wunrecognised-pragmas -Wtyped-holes+ -Wincomplete-patterns -Wincomplete-uni-patterns -Wmissing-fields+ -Wmissing-methods -Wmissing-exported-signatures -Wmissing-monadfail-instances -Wmissing-signatures -Wname-shadowing- -Wnoncanonical-monad-instances -Wnoncanonical-monadfail-instances -Wunused-binds -Wunused-top-binds -Wunused-local-binds -Wunused-pattern-binds -Wunused-imports -Wunused-matches- -Wunused-foralls -Wunused-do-bind -Wwrong-do-bind- -Wtrustworthy-safe -Wwarnings-deprecations -Wdeferred-type-errors+ -Wunused-foralls -Wtabs build-depends:- base >4.9 && <4.12,- template-haskell >=2.12.0.0 && <2.14,+ OneTuple >=0.2.1 && <0.3,+ aeson >=1.1.2.0 && <1.5,+ async >=2.1.1.1 && <2.3,+ base >4.9 && <4.13,+ basement >=0.0.4 && <0.1,+ bytestring >=0.10.8.1 && <0.11,+ cereal >=0.5.4.0 && <0.6,+ cryptonite >=0.23 && <0.26, data-default >=0.7.1.1 && <0.8,- generics-sop >=0.3.2.0 && <0.4,- transformers >=0.5.2.0 && <0.6,- http-client >=0.5.12.1 && <0.6, exceptions >=0.8.3 && <0.11,- bytestring >=0.10.8.2 && <0.11,- cryptonite ==0.25.*,- basement >=0.0.7 && <0.1,+ generics-sop >=0.3.1.0 && <0.4,+ http-client >=0.5.7.1 && <0.6,+ http-client-tls >=0.3.5.1 && <0.4, machines >=0.6.3 && <0.7,+ memory >=0.14.11 && <0.15,+ microlens >=0.4.8.1 && <0.5,+ microlens-aeson >=2.2.0.2 && <2.4,+ microlens-mtl >=0.1.11.0 && <0.2,+ microlens-th >=0.4.1.1 && <0.5,+ mtl >=2.2.1 && <2.3,+ parsec >=3.1.11 && <3.2,+ relapse >=1.0.0.0 && <2.0,+ secp256k1-haskell >=0.1.4 && <0.2, tagged >=0.8.5 && <0.9,- parsec >=3.1.13.0 && <3.2,- memory >=0.14.16 && <0.15,- cereal >=0.5.5.0 && <0.6,- aeson >=1.2.4.0 && <1.4,- async >=2.1.1.1 && <2.3,- text >=1.2.3.0 && <1.3,- mtl >=2.2.2 && <2.3+ template-haskell >=2.11.1.0 && <2.15,+ text >=1.2.2.2 && <1.3,+ transformers >=0.5.2.0 && <0.6,+ vinyl >=0.5.3 && <0.10 - if flag(tls)- cpp-options: -DTLS_MANAGER+ if flag(debug)+ ghc-options: -ddump-splices+ + if flag(solidity)+ cpp-options: -DSOLIDITY_COMPILER+ c-sources:+ ./cbits/solidity_lite.cpp+ extra-libraries:+ solidity+ include-dirs: ./cbits build-depends:- http-client-tls >=0.3.5.3 && <0.4+ containers >=0.5.11.0 && <0.6 -test-suite unit+test-suite live type: exitcode-stdio-1.0 main-is: Spec.hs- hs-source-dirs: unit+ hs-source-dirs: test other-modules:- Network.Ethereum.Web3.Test.MethodDumpSpec- Network.Ethereum.Web3.Test.EncodingSpec- Network.Ethereum.Web3.Test.EventSpec+ Network.Ethereum.Web3.Test.ComplexStorageSpec+ Network.Ethereum.Web3.Test.ERC20Spec+ Network.Ethereum.Web3.Test.LinearizationSpec+ Network.Ethereum.Web3.Test.RegistrySpec+ Network.Ethereum.Web3.Test.SimpleStorageSpec+ Network.Ethereum.Web3.Test.Utils+ Paths_web3 default-language: Haskell2010- ghc-options: -threaded -rtsopts -with-rtsopts=-N+ ghc-options: -funbox-strict-fields -Wduplicate-exports+ -Whi-shadowing -Widentities -Woverlapping-patterns+ -Wpartial-type-signatures -Wunrecognised-pragmas -Wtyped-holes+ -Wincomplete-patterns -Wincomplete-uni-patterns -Wmissing-fields+ -Wmissing-methods -Wmissing-exported-signatures+ -Wmissing-monadfail-instances -Wmissing-signatures -Wname-shadowing+ -Wunused-binds -Wunused-top-binds -Wunused-local-binds+ -Wunused-pattern-binds -Wunused-imports -Wunused-matches+ -Wunused-foralls -Wtabs -threaded -rtsopts -with-rtsopts=-N build-depends:- base >4.9 && <4.12,- hspec-expectations >=0.8.2 && <0.9,- hspec-discover >=2.4.8 && <2.6,- hspec-contrib >=0.4.0 && <0.6,- hspec >=2.4.8 && <2.6,+ OneTuple >=0.2.1 && <0.3,+ aeson >=1.1.2.0 && <1.5,+ async >=2.1.1.1 && <2.3,+ base >4.9 && <4.13,+ basement >=0.0.4 && <0.1,+ bytestring >=0.10.8.1 && <0.11,+ cereal >=0.5.4.0 && <0.6,+ cryptonite >=0.23 && <0.26, data-default >=0.7.1.1 && <0.8,- generics-sop >=0.3.2.0 && <0.4,- transformers >=0.5.2.0 && <0.6,- bytestring >=0.10.8.2 && <0.11,- memory >=0.14.16 && <0.15,+ exceptions >=0.8.3 && <0.11,+ generics-sop >=0.3.1.0 && <0.4,+ hspec >=2.4.4 && <2.6,+ hspec-contrib >=0.4.0 && <0.6,+ hspec-discover >=2.4.4 && <2.6,+ hspec-expectations >=0.8.2 && <0.9,+ http-client >=0.5.7.1 && <0.6,+ http-client-tls >=0.3.5.1 && <0.4,+ machines >=0.6.3 && <0.7,+ memory >=0.14.11 && <0.15,+ microlens >=0.4.8.1 && <0.5,+ microlens-aeson >=2.2.0.2 && <2.4,+ microlens-mtl >=0.1.11.0 && <0.2,+ microlens-th >=0.4.1.1 && <0.5,+ mtl >=2.2.1 && <2.3,+ parsec >=3.1.11 && <3.2,+ random ==1.1.*,+ relapse >=1.0.0.0 && <2.0,+ secp256k1-haskell >=0.1.4 && <0.2,+ split >=0.2.3 && <0.3,+ stm >=2.4.4 && <2.6, tagged >=0.8.5 && <0.9,- split >=0.2.3.3 && <0.3,- time >=1.8.0.2 && <1.9,- text >=1.2.3.0 && <1.3,+ template-haskell >=2.11.1.0 && <2.15,+ text >=1.2.2.2 && <1.3,+ time >=1.6.0 && <1.9,+ transformers >=0.5.2.0 && <0.6,+ vinyl >=0.5.3 && <0.10, web3 -any -test-suite live+test-suite unit type: exitcode-stdio-1.0 main-is: Spec.hs- hs-source-dirs: test+ hs-source-dirs: unit other-modules:- Network.Ethereum.Web3.Test.ComplexStorageSpec- Network.Ethereum.Web3.Test.SimpleStorageSpec- Network.Ethereum.Web3.Test.Utils+ Crypto.Ethereum.Test.EcdsaSpec+ Data.Solidity.Test.AddressSpec+ Data.Solidity.Test.EncodingSpec+ Data.Solidity.Test.IntSpec+ Language.Solidity.Test.CompilerSpec+ Network.Ethereum.Web3.Test.EventSpec+ Network.Ethereum.Web3.Test.LocalAccountSpec+ Network.Ethereum.Web3.Test.MethodDumpSpec+ Paths_web3 default-language: Haskell2010- ghc-options: -threaded -rtsopts -with-rtsopts=-N+ ghc-options: -funbox-strict-fields -Wduplicate-exports+ -Whi-shadowing -Widentities -Woverlapping-patterns+ -Wpartial-type-signatures -Wunrecognised-pragmas -Wtyped-holes+ -Wincomplete-patterns -Wincomplete-uni-patterns -Wmissing-fields+ -Wmissing-methods -Wmissing-exported-signatures+ -Wmissing-monadfail-instances -Wmissing-signatures -Wname-shadowing+ -Wunused-binds -Wunused-top-binds -Wunused-local-binds+ -Wunused-pattern-binds -Wunused-imports -Wunused-matches+ -Wunused-foralls -Wtabs -threaded -rtsopts -with-rtsopts=-N build-depends:- base >4.9 && <4.12,- hspec-expectations >=0.8.2 && <0.9,- hspec-discover >=2.4.8 && <2.6,- hspec-contrib >=0.4.0 && <0.6,- hspec >=2.4.8 && <2.6,- transformers >=0.5.2.0 && <0.6,+ OneTuple >=0.2.1 && <0.3,+ aeson >=1.1.2.0 && <1.5,+ async >=2.1.1.1 && <2.3,+ base >4.9 && <4.13,+ basement >=0.0.4 && <0.1,+ bytestring >=0.10.8.1 && <0.11,+ cereal >=0.5.4.0 && <0.6,+ cryptonite >=0.23 && <0.26, data-default >=0.7.1.1 && <0.8,- bytestring >=0.10.8.2 && <0.11,- memory >=0.14.16 && <0.15,+ exceptions >=0.8.3 && <0.11,+ generics-sop >=0.3.1.0 && <0.4,+ hspec >=2.4.4 && <2.6,+ hspec-contrib >=0.4.0 && <0.6,+ hspec-discover >=2.4.4 && <2.6,+ hspec-expectations >=0.8.2 && <0.9,+ http-client >=0.5.7.1 && <0.6,+ http-client-tls >=0.3.5.1 && <0.4,+ machines >=0.6.3 && <0.7,+ memory >=0.14.11 && <0.15,+ microlens >=0.4.8.1 && <0.5,+ microlens-aeson >=2.2.0.2 && <2.4,+ microlens-mtl >=0.1.11.0 && <0.2,+ microlens-th >=0.4.1.1 && <0.5,+ mtl >=2.2.1 && <2.3,+ parsec >=3.1.11 && <3.2,+ relapse >=1.0.0.0 && <2.0,+ secp256k1-haskell >=0.1.4 && <0.2, tagged >=0.8.5 && <0.9,- split >=0.2.3.3 && <0.3,- async >=2.1.1.1 && <2.3,- time >=1.8.0.2 && <1.9,- text >=1.2.3.0 && <1.3,- stm >=2.4.5.0 && <2.5,+ template-haskell >=2.11.1.0 && <2.15,+ text >=1.2.2.2 && <1.3,+ transformers >=0.5.2.0 && <0.6,+ vinyl >=0.5.3 && <0.10, web3 -any