-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathSpecSyntax.lean
More file actions
76 lines (61 loc) · 2.6 KB
/
Copy pathSpecSyntax.lean
File metadata and controls
76 lines (61 loc) · 2.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import Examples.ERC20.Spec
import Solm.Notation
/-!
# ERC20 — the same spec, written in the Solidity-faithful Solm frontend
This regenerates the entire `ERC20.erc20Contract` (storage, constructor, all six transitions)
using `solidity%` from `Solm.Notation`, then proves the result is **definitionally equal** to the
hand-written AST in `Examples/ERC20/Spec.lean`.
Notes:
* The non-payable `require(msg.value == 0)` guards are implicit, as in Solidity.
* `from`/`to` are Lean keywords, so those parameter names are guillemet-escaped («from», «to»);
`.getId.toString` still yields `"from"`/`"to"`, so the generated AST strings match.
* Transition order matches `erc20Contract.transitions` exactly (needed for `rfl`).
-/
open Solm Solm.Notation
namespace ERC20.Syntax
def contractSyntax : ContractDecl := solidity% contract ERC20 {
mapping(address => uint256) balanceOf;
mapping(address => mapping(address => uint256)) allowance;
uint256 totalSupply;
constructor(uint256 initialSupply) {
balanceOf[msg.sender] = initialSupply;
totalSupply = initialSupply;
}
function approve(address spender, uint256 value) external returns (bool) {
allowance[msg.sender][spender] = value;
return true;
}
function totalSupply() external returns (uint256) {
return totalSupply;
}
function transferFrom(address «from», address «to», uint256 value) external returns (bool) {
uint256 currentAllowance = allowance[«from»][msg.sender];
require(currentAllowance >= value);
uint256 fromBalance = balanceOf[«from»];
require(fromBalance >= value);
allowance[«from»][msg.sender] = currentAllowance - value;
balanceOf[«from»] = (balanceOf[«from»] - value) as uint256;
uint256 toBalance = balanceOf[«to»];
uint256 newToBalance = (toBalance + value) as uint256;
balanceOf[«to»] = newToBalance;
return true;
}
function balanceOf(address owner) external returns (uint256) {
return balanceOf[owner];
}
function transfer(address «to», uint256 value) external returns (bool) {
uint256 fromBalance = balanceOf[msg.sender];
require(fromBalance >= value);
balanceOf[msg.sender] = fromBalance - value;
uint256 toBalance = balanceOf[«to»];
uint256 newToBalance = (toBalance + value) as uint256;
balanceOf[«to»] = newToBalance;
return true;
}
function allowance(address owner, address spender) external returns (uint256) {
return allowance[owner][spender];
}
}
/-- The macro-generated contract is *definitionally* the hand-written one. -/
theorem contractSyntax_eq : contractSyntax = ERC20.erc20Contract := by rfl
end ERC20.Syntax