Skip to content

Commit a484c5e

Browse files
committed
Add Dapp support (close #1)
Add --compile-force-framework flag
1 parent 87a1cb0 commit a484c5e

File tree

11 files changed

+170
-13
lines changed

11 files changed

+170
-13
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ env:
88
- TEST_SUITE=scripts/travis_test_solc.sh
99
- TEST_SUITE=scripts/travis_test_truffle.sh
1010
- TEST_SUITE=scripts/travis_test_embark.sh
11+
- TEST_SUITE=scripts/travis_test_dapp.sh
1112
branches:
1213
only:
1314
- master

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Library to help smart contract compilation. It includes support for:
99
- Direct solc compilation
1010
- [Truffle](https://truffleframework.com/)
1111
- [Embark](https://embark.status.im/)
12+
- [Dapp](https://dapp.tools/dapp/)
1213

1314
The plugin is used in Crytic tools, including:
1415
- [Slither](https://github.com/crytic/slither)

crytic_compile/crytic_compile.py

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
import logging
44

55
from .platform.solc import compile as compile_solc, export as export_solc
6-
from .platform.truffle import compile as compile_truffle, export as export_truffle
7-
from .platform.embark import compile as compile_embark
6+
from .platform.truffle import is_truffle, compile as compile_truffle, export as export_truffle
7+
from .platform.embark import is_embark, compile as compile_embark
8+
from .platform.dapp import is_dapp, compile as compile_dapp#, export as export_truffle
89
from .utils.naming import combine_filename_name
910

1011
logger = logging.getLogger("CryticCompile")
@@ -139,21 +140,33 @@ def _export_standard(self, **kwargs):
139140
json.dump(output, f)
140141

141142

143+
142144
def _run(self, target, **kwargs):
143145

144146
truffle_ignore = kwargs.get('truffle_ignore', False)
145147
embark_ignore = kwargs.get('embark_ignore', False)
146-
147-
# truffle directory
148-
if not truffle_ignore and (os.path.isfile(os.path.join(target, 'truffle.js')) or
149-
os.path.isfile(os.path.join(target, 'truffle-config.js'))):
150-
compile_truffle(self, target, **kwargs)
151-
# embark directory
152-
elif not embark_ignore and os.path.isfile(os.path.join(target, 'embark.json')):
153-
compile_embark(self, target, **kwargs)
154-
# .json or .sol provided
148+
dapp_ignore = kwargs.get('dapp_ignore', False)
149+
150+
compilation_force_framework = kwargs.get('compilation_force_framework', None)
151+
if compilation_force_framework:
152+
if compilation_force_framework == 'truffle':
153+
compile_truffle(self, target, **kwargs)
154+
elif compilation_force_framework == 'embark':
155+
compile_embark(self, target, **kwargs)
156+
elif compilation_force_framework == 'dapp':
157+
compile_dapp(self, target, **kwargs)
155158
else:
156-
compile_solc(self, target, **kwargs)
159+
# truffle directory
160+
if not truffle_ignore and is_truffle(target):
161+
compile_truffle(self, target, **kwargs)
162+
# embark directory
163+
elif not embark_ignore and is_embark(target):
164+
compile_embark(self, target, **kwargs)
165+
elif not dapp_ignore and is_dapp(target):
166+
compile_dapp(self, target, **kwargs)
167+
# .json or .sol provided
168+
else:
169+
compile_solc(self, target, **kwargs)
157170

158171

159172

crytic_compile/cryticparser/cryticparser.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
from . import defaults_flag_in_config
22

33
def init(parser):
4+
5+
group_solc = parser.add_argument_group('Compilation options')
6+
group_solc.add_argument('--compile-force-framework',
7+
help='Force the compilation to a given framework (truffle, embark, dapp)',
8+
action='store',
9+
default=defaults_flag_in_config['compilation_force_framework'])
10+
411
init_solc(parser)
512
init_truffle(parser)
613
init_embark(parser)
14+
init_dapp(parser)
715

816
def init_solc(parser):
917
group_solc = parser.add_argument_group('Solc options')
@@ -56,3 +64,11 @@ def init_embark(parser):
5664
action='store_true',
5765
default=defaults_flag_in_config['embark_overwrite_config'])
5866

67+
def init_dapp(parser):
68+
group_dapp = parser.add_argument_group('Dapp options')
69+
group_dapp.add_argument('--dapp-ignore-compile',
70+
help='Do not run dapp build',
71+
action='store_true',
72+
dest='dapp_ignore_compile',
73+
default=defaults_flag_in_config['dapp_ignore_compile'])
74+

crytic_compile/cryticparser/defaults.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Those are the flags shared by the command line and the config file
22
defaults_flag_in_config = {
3+
'compilation_force_framework': None,
34
'solc': 'solc',
45
'solc_args': None,
56
'solc_disable_warnings': False,
@@ -8,4 +9,5 @@
89
'truffle_build_directory': 'build/contracts',
910
'embark_ignore_compile': False,
1011
'embark_overwrite_config': False,
12+
'dapp_ignore_compile': False,
1113
}

crytic_compile/platform/dapp.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import os
2+
import json
3+
import logging
4+
import glob
5+
6+
7+
import subprocess
8+
9+
from .types import Type
10+
from ..utils.naming import extract_filename, extract_name, combine_filename_name
11+
12+
logger = logging.getLogger("CryticCompile")
13+
14+
15+
def compile(crytic_compile, target, **kwargs):
16+
crytic_compile.type = Type.DAPP
17+
dapp_ignore_compile = kwargs.get('dapp_ignore_compile', False)
18+
dir = os.path.join(target, "out")
19+
20+
if not dapp_ignore_compile:
21+
_run_dapp()
22+
23+
files = glob.glob(dir + '/**/*.sol.json', recursive=True)
24+
for file in files:
25+
with open(file) as f:
26+
targets_json = json.load(f)
27+
for original_contract_name, info in targets_json["contracts"].items():
28+
contract_name = extract_name(original_contract_name)
29+
contract_filename = extract_filename(original_contract_name)
30+
crytic_compile.contracts_name.add(contract_name)
31+
crytic_compile.contracts_filenames[contract_name] = contract_filename
32+
crytic_compile.abis[contract_name] = json.loads(info['abi'])
33+
crytic_compile.init_bytecodes[contract_name] = info['bin']
34+
crytic_compile.runtime_bytecodes[contract_name] = info['bin-runtime']
35+
36+
for path, info in targets_json["sources"].items():
37+
crytic_compile.filenames.add(path)
38+
crytic_compile.asts[path] = info['AST']
39+
40+
41+
def export(crytic_compile, **kwargs):
42+
export_dir = kwargs.get('export_dir', 'crytic-export')
43+
if not os.path.exists(export_dir):
44+
os.makedirs(export_dir)
45+
path = os.path.join(export_dir, "combined_solc.json")
46+
47+
with open(path, 'w') as f:
48+
contracts = dict()
49+
for contract_name in crytic_compile.contracts_name:
50+
abi = str(crytic_compile.abi(contract_name))
51+
abi = abi.replace('\'', '\"')
52+
abi = abi.replace('True', 'true')
53+
abi = abi.replace('False', 'false')
54+
abi = abi.replace(' ', '')
55+
exported_name = combine_filename_name(crytic_compile.contracts_filenames[contract_name], contract_name)
56+
contracts[exported_name] = {
57+
'srcmap': '',
58+
'srcmap-runtime': '',
59+
'abi': abi,
60+
'bin': crytic_compile.init_bytecode(contract_name),
61+
'bin-runtime': crytic_compile.runtime_bytecode(contract_name)
62+
}
63+
64+
sources = {filename : {"AST": ast} for (filename, ast) in crytic_compile.asts.items()}
65+
sourceList = crytic_compile.filenames
66+
67+
output = {'sources' : sources,
68+
'sourceList' : sourceList,
69+
'contracts': contracts}
70+
71+
json.dump(output, f)
72+
73+
def is_dapp(target):
74+
"""
75+
Heuristic used: check if "dapp build" is present in Makefile
76+
:param target:
77+
:return:
78+
"""
79+
makefile = os.path.join(target, "Makefile")
80+
if os.path.isfile(makefile):
81+
with open(makefile) as f:
82+
txt = f.read()
83+
return "dapp build" in txt
84+
return False
85+
86+
def _run_dapp():
87+
cmd = ["dapp", "build"]
88+
89+
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
90+
_, _ = process.communicate()

crytic_compile/platform/embark.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,6 @@ def compile(crytic_compile, target, **kwargs):
6666
crytic_compile.init_bytecodes[contract_name] = info['bin'].replace('0x', '')
6767
if 'bin-runtime' in info:
6868
crytic_compile.runtime_bytecodes[contract_name] = info['bin-runtime'].replace('0x', '')
69+
70+
def is_embark(target):
71+
return os.path.isfile(os.path.join(target, 'embark.json'))

crytic_compile/platform/truffle.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,9 @@ def export(crytic_compile, **kwargs):
7575
"deployedBytecode": "0x" + crytic_compile.runtime_bytecode(contract_name),
7676
"ast": crytic_compile.ast(filename)
7777
}
78-
json.dump(output, f)
78+
json.dump(output, f)
79+
80+
81+
def is_truffle(target):
82+
return (os.path.isfile(os.path.join(target, 'truffle.js')) or
83+
os.path.isfile(os.path.join(target, 'truffle-config.js')))

crytic_compile/platform/types.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ class Type(Enum):
44
SOLC = 1
55
TRUFFLE = 2
66
EMBARK = 3
7+
DAPP = 4
78

scripts/travis_test_dapp.sh

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/usr/bin/env bash
2+
3+
### Test dapp integration
4+
5+
mkdir test_dapp
6+
cd test_dapp
7+
8+
9+
curl https://nixos.org/nix/install | sh
10+
. "$HOME/.nix-profile/etc/profile.d/nix.sh"
11+
git clone --recursive https://github.com/dapphub/dapptools $HOME/.dapp/dapptools
12+
nix-env -f $HOME/.dapp/dapptools -iA dapp seth solc hevm ethsign
13+
14+
dapp init
15+
16+
crytic-compile .
17+
18+
DIFF=$(diff crytic-export/contracts.json ../tests/expected/dapp-demo.json)
19+
if [ $DIFF != "" ]
20+
then
21+
echo "Dapp test failed"
22+
exit -1
23+
fi
24+

0 commit comments

Comments
 (0)