// from https://github.com/ConsenSys/Tokens/blob/fdf687c69d998266a95f15216b1955a4965a0a6d/contracts/eip20/
pragmasolidity^0.4.25;contractEIP20Interface{/* This is a slight change to the ERC20 base standard.
function totalSupply() constant returns (uint256 supply);
is replaced with:
uint256 public totalSupply;
This automatically creates a getter function for the totalSupply.
This is moved to the base contract since public getter functions are not
currently recognised as an implementation of the matching abstract
function by the compiler.
*//// total amount of tokens
uint256publictotalSupply;/// @param _owner The address from which the balance will be retrieved
/// @return The balance
functionbalanceOf(address_owner)publicviewreturns(uint256balance);/// @notice send `_value` token to `_to` from `msg.sender`
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
/// @return Whether the transfer was successful or not
functiontransfer(address_to,uint256_value)publicreturns(boolsuccess);/// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
/// @param _from The address of the sender
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
/// @return Whether the transfer was successful or not
functiontransferFrom(address_from,address_to,uint256_value)publicreturns(boolsuccess);/// @notice `msg.sender` approves `_spender` to spend `_value` tokens
/// @param _spender The address of the account able to transfer the tokens
/// @param _value The amount of tokens to be approved for transfer
/// @return Whether the approval was successful or not
functionapprove(address_spender,uint256_value)publicreturns(boolsuccess);/// @param _owner The address of the account owning tokens
/// @param _spender The address of the account able to transfer the tokens
/// @return Amount of remaining tokens allowed to spent
functionallowance(address_owner,address_spender)publicviewreturns(uint256remaining);// solhint-disable-next-line no-simple-event-func-name
eventTransfer(addressindexed_from,addressindexed_to,uint256_value);eventApproval(addressindexed_owner,addressindexed_spender,uint256_value);}contractEIP20isEIP20Interface{uint256constantprivateMAX_UINT256=2**256-1;mapping(address=>uint256)publicbalances;mapping(address=>mapping(address=>uint256))publicallowed;/*
NOTE:
The following variables are OPTIONAL vanities. One does not have to include them.
They allow one to customise the token contract & in no way influences the core functionality.
Some wallets/interfaces might not even bother to look at this information.
*/stringpublicname;//fancy name: eg Simon Bucks
uint8publicdecimals;//How many decimals to show.
stringpublicsymbol;//An identifier: eg SBX
functionEIP20(uint256_initialAmount,string_tokenName,uint8_decimalUnits,string_tokenSymbol)public{balances[msg.sender]=_initialAmount;// Give the creator all initial tokens
totalSupply=_initialAmount;// Update total supply
name=_tokenName;// Set the name for display purposes
decimals=_decimalUnits;// Amount of decimals for display purposes
symbol=_tokenSymbol;// Set the symbol for display purposes
}functiontransfer(address_to,uint256_value)publicreturns(boolsuccess){require(balances[msg.sender]>=_value);balances[msg.sender]-=_value;balances[_to]+=_value;emitTransfer(msg.sender,_to,_value);//solhint-disable-line indent, no-unused-vars
returntrue;}functiontransferFrom(address_from,address_to,uint256_value)publicreturns(boolsuccess){uint256allowance=allowed[_from][msg.sender];require(balances[_from]>=_value&&allowance>=_value);balances[_to]+=_value;balances[_from]-=_value;if(allowance<MAX_UINT256){allowed[_from][msg.sender]-=_value;}emitTransfer(_from,_to,_value);//solhint-disable-line indent, no-unused-vars
returntrue;}functionbalanceOf(address_owner)publicviewreturns(uint256balance){returnbalances[_owner];}functionapprove(address_spender,uint256_value)publicreturns(boolsuccess){allowed[msg.sender][_spender]=_value;emitApproval(msg.sender,_spender,_value);//solhint-disable-line indent, no-unused-vars
returntrue;}functionallowance(address_owner,address_spender)publicviewreturns(uint256remaining){returnallowed[_owner][_spender];}}
Before running the evm_cfg_builder tool, we have some requirements to met.
1
virtualenv -p /usr/bin/python3.6 venv
1
2
3
4
5
Running virtualenv with interpreter /usr/bin/python3.6
Using base prefix '/usr'New python executable in /tmp/cfg_test/evm_cfg_builder/examples/venv/bin/python3.6
Also creating executable in /tmp/cfg_test/evm_cfg_builder/examples/venv/bin/python
Installing setuptools, pip, wheel...done.
Activate the virtualenv
1
source venv/bin/activate
Installing EVM CFG Builder
With the virtualenv activated, install the crytic evm-cfg-builder tool
1
pip3 install evm-cfg-builder
A success installation process will download and setup the required dependencies of the toolkit
WARNING: pip is being invoked by an old script wrapper. This will fail in a future version of pip.
Please see https://github.com/pypa/pip/issues/5599 for advice on fixing the underlying issue.
To avoid this problem you can invoke Python with '-m pip' instead of running pip directly.
Defaulting to user installation because normal site-packages is not writeable
Collecting evm-cfg-builder
Downloading evm-cfg-builder-0.3.1.tar.gz (1.3 MB)|████████████████████████████████| 1.3 MB 1.3 MB/s
Preparing metadata (setup.py) ... doneCollecting crytic-compile>=0.1.13
Downloading crytic_compile-0.2.3-py3-none-any.whl (87 kB)|████████████████████████████████|87 kB 3.8 MB/s
Collecting pyevmasm>=0.1.1
Downloading pyevmasm-0.2.3-py3-none-any.whl (15 kB)Collecting pysha3>=1.0.2
Downloading pysha3-1.0.2-cp36-cp36m-manylinux1_x86_64.whl (127 kB)|████████████████████████████████|127 kB 2.9 MB/s
Collecting future
Downloading future-0.18.2.tar.gz (829 kB)|████████████████████████████████|829 kB 3.0 MB/s
Preparing metadata (setup.py) ... doneBuilding wheels for collected packages: evm-cfg-builder, future
Building wheel for evm-cfg-builder (setup.py) ... done Created wheel for evm-cfg-builder: filename=evm_cfg_builder-0.3.1-py3-none-any.whl size=1266352sha256=728c18abb3c9bc88187114ee252bc2083171fd0c89b354497c27f893e7e6214d
Stored in directory: /home/r00t/.cache/pip/wheels/79/61/a6/44d291f111ea801eb83cd667d0c049f605d054c8ad8c065aa4
Building wheel for future (setup.py) ... done Created wheel for future: filename=future-0.18.2-py3-none-any.whl size=493275sha256=fd0110fe805d02f9ce1c0c91312dbaced731711b64f1c24245794d5cc667bd7e
Stored in directory: /home/r00t/.cache/pip/wheels/6e/9c/ed/4499c9865ac1002697793e0ae05ba6be33553d098f3347fb94
Successfully built evm-cfg-builder future
Installing collected packages: pysha3, future, pyevmasm, crytic-compile, evm-cfg-builder
WARNING: The scripts futurize and pasteurize are installed in '/home/r00t/.local/bin' which is not on PATH.
Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
WARNING: The script evmasm is installed in '/home/r00t/.local/bin' which is not on PATH.
Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
WARNING: The script crytic-compile is installed in '/home/r00t/.local/bin' which is not on PATH.
Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
WARNING: The script evm-cfg-builder is installed in '/home/r00t/.local/bin' which is not on PATH.
Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
Successfully installed crytic-compile-0.2.3 evm-cfg-builder-0.3.1 future-0.18.2 pyevmasm-0.2.3 pysha3-1.0.2
Run the crytic evm-cfg-builder
To launch the evm-cfg-builder tool, a one line command is needed.
1
evm-cfg-builder --export-dot . token-runtime.evm
The crytic evm-cfg-builder output in this analysis is shown below
Since we configure evm-cfg-builder analysis to generate Graphviz .dot file with the option --export-dot, the files are created in the same directory as our source code. We can find the FULL graph and a file representing each function in the code
In this example, for a contract with 112 source code lines and 6431 bytes in compiled code, the output analysis time is 0.81s. Quite fast!
1
evm-cfg-builder --export-dot . token-runtime.evm 0,75s user 0,06s system 100% cpu 0,811 total
Sample views of created graphs
Some images of the output analysis. Enjoy.
Graph of the allowance() function
Graph of the balanceof(address) function
Graph of the decimals() function
Graph of the dispatcher() function
Graph of the fallback() function
Graph of the totalSupply() function
Graph of the transferFrom() function
Conclusion
The Crytic evm-cfg-builder tool is one of the available ways to convert the compiled code into a visual representation. However, it still provides a very basic overview of the smart contract code blocks without applying any of the available optimizations to final graph result. As a consecuence, the final graph contains more edges, nodes and overall complexity is increased.
Thanks for checking this out and I hope you found the info useful! If you have any questions, don't hesitate to write me a comment below. And remember that if you like to see more content on, just let me know it and share this post with your colleges, co-workers, FFF, etc.