Skip to content

Commit 1bf9d7b

Browse files
Update README.md and Add smart contract examples
1 parent fe3def2 commit 1bf9d7b

File tree

1,879 files changed

+781239
-20
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,879 files changed

+781239
-20
lines changed

README.md

+32-3
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,38 @@ The main components of WANA is as follow.
2222
+ `structure.py` and `runtime.py` represent WebAssembly bytecode structure and virtual machine runtime structure.
2323
+ `number.py`, `utils.py` and `logger.py` are helper modules.
2424

25+
## Prerequisites
26+
The following Python packages are required.
27+
+ six==1.14.0
28+
+ func_timeout==4.3.5
29+
+ z3-solver==4.8.8.0
30+
31+
The project was developed under Ubuntu 18.04, therefore it is compatible with later version in principle.
32+
33+
2534
## Usage
26-
Firstly, the prerequisites in [requirements.txt](./requirements.txt) should be correctly installed.
35+
There should be a compiled smart contract in wasm format. The EOSIO and Ethereum smart contract could be
36+
compiled as follow.
37+
38+
### EOSIO smart contract
39+
The EOSIO smart contract is developed using cpp or rust, like [appdemo](./examples/EOSIO_contracts/appdemo/appdemo.cpp).
40+
Firstly, installing the [eosio.cdt](https://github.com/EOSIO/eosio.cdt) according to its
41+
[README](https://github.com/EOSIO/eosio.cdt/blob/master/README.md). Then, using the following command to compile the
42+
above smart contract.
43+
```bash
44+
eosio-cpp appdemo.cpp -o appdemo.wasm
45+
```
2746

47+
### Ethereum smart contract
48+
The type of Ethereum smart contract source code is solidity. At present, there are some tools to complete the process
49+
that compile smart contract from solidity to WebAssembly. For example, [soll](https://github.com/second-state/SOLL) is
50+
a more mature tool. After setting up the environment of soll, using the following command to compile a smart contract,
51+
for example, [Router.sol](./examples/Ethereum_contracts/delegatecall_samples/Router.sol).
52+
```bash
53+
~/soll/build/tools/soll/soll Router.sol
54+
```
55+
56+
### Analysis
2857
The following command will analyze the EOSIO smart contract `contract.wasm` with timeout 20 seconds. The `-t` is
2958
optional, the symbolic execution won't be interrupted until complete analysis if `-t` not set.
3059
```bash
@@ -53,5 +82,5 @@ contract.wasm: forged transfer notification found
5382
1. https://webassembly.org/
5483
2. https://github.com/WebAssembly/
5584
3. https://developer.mozilla.org/en-US/docs/WebAssembly
56-
57-
85+
4. https://github.com/EOSIO/eosio.cdt
86+
5. https://github.com/second-state/SOLL

bug_analyzer.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def cur_state_analysis(store, frame, stack, expr, pc, solver=None):
3737
return
3838

3939
if global_vars.fake_detection_mode:
40-
fake_eos_analysis(store, frame, expr, pc, solver)
40+
fake_eos_analysis(store, frame, stack, expr, pc, solver)
4141
return
4242

4343
if _is_transfer_function(store, frame, stack, expr, pc):
@@ -164,7 +164,7 @@ def detect_forged_transfer(store, frame, index):
164164
165165
"""
166166

167-
global_vars.detect()
167+
global_vars.forged_detect()
168168

169169
module = frame.module
170170
table = store.tables[module.tableaddrs[0]]
@@ -298,14 +298,14 @@ def detect_fake_eos(vm, name) -> None:
298298
func_type.args = bytearray([bin_format.i64, bin_format.i64, bin_format.i64])
299299
func_type.rets = bytearray()
300300
apply_func = vm.store.funcs[vm.module_instance.funcaddrs[global_vars.apply_function_address]]
301-
global_vars.detect()
301+
global_vars.fake_detect()
302302
if apply_func.functype == func_type:
303303
params = utils.gen_symbolic_args(apply_func)
304304
global_vars.apply_params = params
305305
params[0] = utils.eos_abi_to_int(name)
306306
params[2] = utils.eos_abi_to_int('transfer')
307307
init_constraints = [params[0] != params[1], params[1] != utils.eos_abi_to_int('eosio.token')]
308-
vm.exec_by_address(global_vars.apply_function_address, params, False, init_constraints)
308+
vm.exec_by_address(global_vars.apply_function_address, params, init_constraints)
309309
global_vars.sym_exec() # set the detection mode to False
310310

311311

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
{
2+
"____comment": "This file was generated by eosio-abigen. DO NOT EDIT - 2018-05-15T01:04:39",
3+
"types": [],
4+
"structs": [{
5+
"name": "profile",
6+
"base": "",
7+
"fields": [{
8+
"name": "account",
9+
"type": "account_name"
10+
},{
11+
"name": "username",
12+
"type": "string"
13+
},{
14+
"name": "age",
15+
"type": "uint32"
16+
},{
17+
"name": "bio",
18+
"type": "string"
19+
}
20+
]
21+
},{
22+
"name": "hello",
23+
"base": "",
24+
"fields": [{
25+
"name": "account",
26+
"type": "account_name"
27+
}
28+
]
29+
},{
30+
"name": "create",
31+
"base": "",
32+
"fields": [{
33+
"name": "account",
34+
"type": "account_name"
35+
},{
36+
"name": "username",
37+
"type": "string"
38+
},{
39+
"name": "age",
40+
"type": "uint32"
41+
},{
42+
"name": "bio",
43+
"type": "string"
44+
}
45+
]
46+
},{
47+
"name": "get",
48+
"base": "",
49+
"fields": [{
50+
"name": "account",
51+
"type": "account_name"
52+
}
53+
]
54+
},{
55+
"name": "update",
56+
"base": "",
57+
"fields": [{
58+
"name": "account",
59+
"type": "account_name"
60+
},{
61+
"name": "username",
62+
"type": "string"
63+
},{
64+
"name": "age",
65+
"type": "uint32"
66+
},{
67+
"name": "bio",
68+
"type": "string"
69+
}
70+
]
71+
},{
72+
"name": "remove",
73+
"base": "",
74+
"fields": [{
75+
"name": "account",
76+
"type": "account_name"
77+
}
78+
]
79+
},{
80+
"name": "byage",
81+
"base": "",
82+
"fields": [{
83+
"name": "age",
84+
"type": "uint32"
85+
}
86+
]
87+
},{
88+
"name": "agerange",
89+
"base": "",
90+
"fields": [{
91+
"name": "young",
92+
"type": "uint32"
93+
},{
94+
"name": "old",
95+
"type": "uint32"
96+
}
97+
]
98+
}
99+
],
100+
"actions": [{
101+
"name": "hello",
102+
"type": "hello",
103+
"ricardian_contract": ""
104+
},{
105+
"name": "create",
106+
"type": "create",
107+
"ricardian_contract": ""
108+
},{
109+
"name": "get",
110+
"type": "get",
111+
"ricardian_contract": ""
112+
},{
113+
"name": "update",
114+
"type": "update",
115+
"ricardian_contract": ""
116+
},{
117+
"name": "remove",
118+
"type": "remove",
119+
"ricardian_contract": ""
120+
},{
121+
"name": "byage",
122+
"type": "byage",
123+
"ricardian_contract": ""
124+
},{
125+
"name": "agerange",
126+
"type": "agerange",
127+
"ricardian_contract": ""
128+
}
129+
],
130+
"tables": [{
131+
"name": "profile",
132+
"index_type": "i64",
133+
"key_names": [
134+
"account"
135+
],
136+
"key_types": [
137+
"account_name"
138+
],
139+
"type": "profile"
140+
}
141+
],
142+
"clauses": []
143+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/* appdemo.cpp
2+
* Jack DiSalvatore
3+
*/
4+
#include <appdemo.hpp>
5+
6+
void appdemo::hello(account_name account) {
7+
print("Hello ", name{account});
8+
}
9+
10+
void appdemo::create(const account_name account,
11+
const string& username,
12+
uint32_t age,
13+
const string& bio) {
14+
require_auth(account);
15+
16+
profile_table profiles(_self, _self);
17+
18+
auto itr = profiles.find(account);
19+
20+
eosio_assert(itr == profiles.end(), "Account already exists");
21+
22+
profiles.emplace(account, [&](auto& p) {
23+
p.account = account;
24+
p.username = username;
25+
p.age = age;
26+
p.bio = bio;
27+
});
28+
}
29+
30+
void appdemo::get(const account_name account) {
31+
profile_table profiles(_self, _self);
32+
33+
auto itr = profiles.find(account);
34+
35+
eosio_assert(itr != profiles.end(), "Account does not exist");
36+
37+
print("Account: ", name{itr->account}, " , ");
38+
print("Username: ", itr->username.c_str(), " , ");
39+
print("Age: ", itr->age , " , ");
40+
print("Bio: ", itr->bio.c_str());
41+
}
42+
43+
void appdemo::update(const account_name account,
44+
const string& username,
45+
uint32_t age,
46+
const string& bio) {
47+
require_auth(account);
48+
49+
profile_table profiles(_self, _self);
50+
51+
auto itr = profiles.find(account);
52+
53+
eosio_assert(itr != profiles.end(), "Account does not exist");
54+
55+
profiles.modify(itr, account, [&](auto& p) {
56+
p.username = username;
57+
p.age = age;
58+
p.bio = bio;
59+
});
60+
}
61+
62+
void appdemo::remove(const account_name account) {
63+
require_auth(account);
64+
65+
profile_table profiles(_self, _self);
66+
67+
auto itr = profiles.find(account);
68+
69+
eosio_assert(itr != profiles.end(), "Account does not exist");
70+
71+
profiles.erase(itr);
72+
print(name{account} , " deleted!");
73+
}
74+
75+
void appdemo::byage(uint32_t age) {
76+
print("Checking age: ", age, "\n");
77+
profile_table profiles(_self, _self);
78+
79+
// get an interface to the 'profiles' containter
80+
// that looks up a profile by its age
81+
auto age_index = profiles.get_index<N(age)>();
82+
83+
// lower_bound is an associative container operator
84+
// which returns an iterator to the first element that is
85+
// to lower then the key
86+
// we use lower bound, because we want to find everyone
87+
// who is this age, there may be multiple
88+
auto itr = age_index.lower_bound(age);
89+
90+
for(; itr != age_index.end() && itr->age == age; ++itr) {
91+
print(itr->username.c_str(), " is ", itr->age, " years old\n");
92+
}
93+
}
94+
95+
void appdemo::agerange(uint32_t young, uint32_t old) {
96+
profile_table profiles(_self, _self);
97+
98+
auto age_index = profiles.get_index<N(age)>();
99+
100+
auto begin = age_index.lower_bound(young);
101+
auto end = age_index.upper_bound(old);
102+
103+
for_each(begin, end, [&](auto& p) {
104+
print(p.username.c_str(), " is ", p.age, " years old\n");
105+
});
106+
}

0 commit comments

Comments
 (0)