Skip to content

Commit 678f5dc

Browse files
authored
Merge pull request #195 from lefterislazar/hevm-erc20
Hevm ERC20
2 parents f10de80 + d3e9e66 commit 678f5dc

File tree

2 files changed

+270
-0
lines changed

2 files changed

+270
-0
lines changed

tests/hevm/pass/erc20/erc20.act

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
constructor of Token
2+
interface constructor(uint256 _totalSupply)
3+
4+
iff CALLVALUE == 0
5+
6+
creates
7+
8+
uint256 totalSupply := _totalSupply
9+
mapping(address => uint) balanceOf := [CALLER := _totalSupply]
10+
mapping(address=>mapping(address=>uint)) allowance := []
11+
12+
13+
behaviour transfer of Token
14+
interface transfer(uint256 value, address to)
15+
16+
iff
17+
18+
CALLVALUE == 0
19+
inRange(uint256, balanceOf[CALLER] - value)
20+
CALLER =/= to => inRange(uint256, balanceOf[to] + value)
21+
22+
case CALLER =/= to:
23+
24+
storage
25+
26+
balanceOf[CALLER] => balanceOf[CALLER] - value
27+
balanceOf[to] => balanceOf[to] + value
28+
29+
returns 1
30+
31+
case CALLER == to:
32+
33+
returns 1
34+
35+
36+
behaviour transferFrom of Token
37+
interface transferFrom(address src, address dst, uint amount)
38+
39+
iff
40+
41+
amount <= balanceOf[src]
42+
src =/= dst => inRange(uint256, balanceOf[dst] + amount)
43+
CALLER =/= src => inRange(uint256, allowance[src][CALLER] - amount)
44+
CALLVALUE == 0
45+
46+
case src =/= dst and CALLER == src:
47+
48+
storage
49+
50+
balanceOf[src] => balanceOf[src] - amount
51+
balanceOf[dst] => balanceOf[dst] + amount
52+
53+
returns 1
54+
55+
case src =/= dst and CALLER =/= src and allowance[src][CALLER] == 2^256 - 1:
56+
57+
storage
58+
59+
balanceOf[src] => balanceOf[src] - amount
60+
balanceOf[dst] => balanceOf[dst] + amount
61+
62+
returns 1
63+
64+
case src =/= dst and CALLER =/= src and allowance[src][CALLER] < 2^256 - 1:
65+
66+
storage
67+
68+
allowance[src][CALLER] => allowance[src][CALLER] - amount
69+
balanceOf[src] => balanceOf[src] - amount
70+
balanceOf[dst] => balanceOf[dst] + amount
71+
72+
returns 1
73+
74+
case src == dst and CALLER =/= src and allowance[src][CALLER] < 2^256 - 1:
75+
76+
storage
77+
78+
allowance[src][CALLER] => allowance[src][CALLER] - amount
79+
80+
returns 1
81+
82+
case src == dst and (CALLER == src or allowance[src][CALLER] == 2^256 - 1):
83+
84+
returns 1
85+
86+
87+
behaviour approve of Token
88+
interface approve(address spender, uint amount)
89+
90+
iff
91+
92+
inRange(uint256, amount)
93+
CALLVALUE == 0
94+
95+
case CALLER =/= spender:
96+
97+
storage
98+
99+
allowance[CALLER][spender] => amount
100+
101+
returns 1
102+
103+
case CALLER == spender:
104+
105+
returns 1
106+
107+
108+
behaviour burn of Token
109+
interface burn(uint256 amount)
110+
111+
iff
112+
113+
CALLVALUE == 0
114+
inRange(uint256, totalSupply - amount)
115+
inRange(uint256, balanceOf[CALLER] - amount)
116+
117+
storage
118+
119+
totalSupply => totalSupply - amount
120+
balanceOf[CALLER] => balanceOf[CALLER] - amount
121+
122+
returns 1
123+
124+
125+
behaviour burnFrom of Token
126+
interface burnFrom(address src, uint256 amount)
127+
128+
iff
129+
amount <= totalSupply
130+
amount <= balanceOf[src]
131+
CALLER =/= src => amount <= allowance[src][CALLER]
132+
CALLVALUE == 0
133+
134+
case CALLER =/= src and allowance[src][CALLER] == 2^256 - 1:
135+
136+
storage
137+
138+
totalSupply => totalSupply - amount
139+
balanceOf[src] => balanceOf[src] - amount
140+
141+
returns 1
142+
143+
case CALLER =/= src and allowance[src][CALLER] < 2^256 - 1:
144+
145+
storage
146+
147+
totalSupply => totalSupply - amount
148+
allowance[src][CALLER] => allowance[src][CALLER] - amount
149+
balanceOf[src] => balanceOf[src] - amount
150+
151+
returns 1
152+
153+
case CALLER == src:
154+
155+
storage
156+
157+
totalSupply => totalSupply - amount
158+
balanceOf[src] => balanceOf[src] - amount
159+
160+
returns 1
161+
162+
ensures
163+
164+
pre(balanceOf[src]) - post(balanceOf[src]) == pre(totalSupply) - post(totalSupply)
165+
166+
167+
behaviour mint of Token
168+
interface mint(address dst, uint256 amount)
169+
170+
iff in range uint256
171+
172+
totalSupply + amount
173+
balanceOf[dst] + amount
174+
175+
iff
176+
177+
CALLVALUE == 0
178+
179+
storage
180+
181+
totalSupply => totalSupply + amount
182+
balanceOf[dst] => balanceOf[dst] + amount
183+
184+
returns 1
185+
186+
187+
// View functions:
188+
189+
behaviour totalSupply of Token
190+
interface totalSupply()
191+
192+
iff
193+
194+
CALLVALUE == 0
195+
196+
returns pre(totalSupply)
197+
198+
behaviour balanceOf of Token
199+
interface balanceOf(address idx)
200+
201+
iff
202+
203+
CALLVALUE == 0
204+
205+
returns pre(balanceOf[idx])
206+
207+
behaviour allowance of Token
208+
interface allowance(address idx1, address idx2)
209+
210+
iff
211+
212+
CALLVALUE == 0
213+
214+
returns pre(allowance[idx1][idx2])

tests/hevm/pass/erc20/erc20.sol

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
pragma solidity >=0.8.0;
2+
3+
contract Token {
4+
uint256 public totalSupply;
5+
mapping (address => uint256) public balanceOf;
6+
mapping (address => mapping (address => uint256)) public allowance;
7+
8+
constructor(uint256 _totalSupply) {
9+
totalSupply = _totalSupply;
10+
balanceOf[msg.sender] = _totalSupply;
11+
}
12+
13+
14+
function approve(address spender, uint256 value) public returns (bool) {
15+
if(spender != msg.sender) {
16+
allowance[msg.sender][spender] = value;
17+
}
18+
return true;
19+
}
20+
21+
function transfer(uint256 value, address to) public returns (bool) {
22+
balanceOf[msg.sender] = balanceOf[msg.sender] - value;
23+
balanceOf[to] = balanceOf[to] + value;
24+
return true;
25+
}
26+
27+
function transferFrom(address from, address to, uint256 value) public returns (bool) {
28+
if(from != msg.sender && allowance[from][msg.sender] != type(uint256).max) {
29+
allowance[from][msg.sender] = allowance[from][msg.sender] - value;
30+
}
31+
balanceOf[from] = balanceOf[from] - value;
32+
balanceOf[to] = balanceOf[to] + value;
33+
return true;
34+
}
35+
36+
function burn(uint256 value) public returns (bool) {
37+
totalSupply = totalSupply - value;
38+
balanceOf[msg.sender] = balanceOf[msg.sender] - value;
39+
return true;
40+
}
41+
42+
function burnFrom(address account, uint256 value) public returns (bool) {
43+
if(account != msg.sender && allowance[account][msg.sender] != type(uint256).max) {
44+
allowance[account][msg.sender] = allowance[account][msg.sender] - value;
45+
}
46+
totalSupply = totalSupply - value;
47+
balanceOf[account] = balanceOf[account] - value;
48+
return true;
49+
}
50+
51+
function mint(address account, uint256 value) public returns (bool) {
52+
totalSupply = totalSupply + value;
53+
balanceOf[account] = balanceOf[account] + value;
54+
return true;
55+
}
56+
}

0 commit comments

Comments
 (0)