Skip to content

Commit 8b2e75f

Browse files
extends and improves tracking sums pattern
1 parent 2f98f8e commit 8b2e75f

File tree

3 files changed

+70
-33
lines changed

3 files changed

+70
-33
lines changed

docs/user-guide/patterns/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Certain patterns often occur in specification files. This chapter describes
55
some of these patterns.
66

77
```{toctree}
8-
sums.md
8+
sums.rst
99
partial-apply.md
1010
safe-assum.md
1111
require-invariants.md

docs/user-guide/patterns/sums.md

Lines changed: 0 additions & 32 deletions
This file was deleted.

docs/user-guide/patterns/sums.rst

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
.. index::
2+
single: sums
3+
4+
Tracking Sums
5+
=============
6+
7+
This section deals with tracking sums of values. The quintessential example for
8+
needing to track sums is from ERC-20 contracts, where :solidity:`totalSupply()`
9+
must be the sum of all balances. This is the example we shall use here,
10+
namely the :clink:`ERC20</DEFI/ERC20/contracts/ERC20.sol>` contract from the
11+
:clink:`Examples</>` repository.
12+
13+
14+
Trying to verify the sum of two balances
15+
----------------------------------------
16+
Often one needs a invariant like :cvl:`sumOfTwo` below:
17+
18+
.. code-block:: cvl
19+
20+
invariant sumOfTwo(address a, address b)
21+
(a != b) => (balanceOf(a) + balanceOf(b) <= to_mathint(totalSupply()));
22+
23+
If we run this invariant, the Prover will find a violations.
24+
An example of such a violation is summarized in the table below.
25+
In this example the function called was :cvl:`tranferFrom(c, a, 2)`,
26+
where :solidity:`c` is an address different from :solidity:`a` and :solidity:`b`.
27+
28+
.. list-table:: Counter example
29+
:header-rows: 1
30+
:align: center
31+
32+
* -
33+
- Before :cvl:`tranferFrom`
34+
- After
35+
36+
* - :cvl:`balanceOf(a)`
37+
- 1
38+
- 3
39+
40+
* - :cvl:`balanceOf(b)`
41+
- 2
42+
- 2
43+
44+
* - :cvl:`balanceOf(c)`
45+
- 3
46+
- 1
47+
48+
* - :cvl:`totalSupply()`
49+
- 3
50+
- 3
51+
52+
* - :cvl:`sumOfTwo(a, b)`
53+
- **true** (3 >= 1+2)
54+
- **false** (3 < 3+2)
55+
56+
We see that the Prover cannot verify :cvl:`sumOfTwo` invariant without us adding unsound
57+
assumptions. So instead, we shall prove a stronger property, as explained next.
58+
59+
60+
Equality of sum of balances and total supply
61+
--------------------------------------------
62+
The preferred solution to tracking sums is using a hook and a ghost, as shown below.
63+
64+
.. cvlinclude:: ../../../Examples/DEFI/ERC20/certora/specs/ERC20Fixed.spec
65+
:lines: 98-106, 115-116
66+
:caption: :clink:`Total supply is sum of balances</DEFI/ERC20/certora/specs/ERC20Fixed.spec>`
67+
68+
Once this invariant is proved, we can require properties like the one in
69+
:cvl:`sumOfTwo` above.

0 commit comments

Comments
 (0)