Skip to content

Commit 92fcedf

Browse files
committed
More tweaks to readme, tests, license - ready for mesh release
1 parent 4fc1896 commit 92fcedf

File tree

5 files changed

+351
-5
lines changed

5 files changed

+351
-5
lines changed

LICENSE

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
All files except
22
* the [.sml], [.ml] and [.thy] files in [lem] directory and
3+
the files in elle/tests
34
are distributed under Apache License Version 2.0.
45

56
The [.sml], [.ml] and [.thy] files in [lem] directory are distributed under the terms in [lem/lem-license].
67

8+
The files in elle/tests are property of their owners, as described in elle/README.
9+
Other files in elle/tests are subject to the Apache License Version 2.0.
710

811

912
Apache License

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ once you have built the `llllc` executable:
4949

5050
`cd elle/tests`
5151

52-
`../generated/llllc add.lll`
52+
`../generated/llllc echo.lll`
5353

5454
(or any other lll file in the directory)
5555

elle/tests/README

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ Ones marked with star should compile correctly on the current Elle.
44

55
add.lll - simple addition expression *
66
def.lll - macro definition *
7-
echo.lll - Dan Ellison's echo contract *
8-
erc20.lll - Ben Edgington's ERC20 token
7+
echo.lll - Dan Ellison's echo contract (https://media.consensys.net/compiling-your-first-contract-in-lll-28d5a9dd2e3a)*
8+
erc20.lll - Ben Edgington's ERC20 token (https://github.com/benjaminion/LLL_erc20/blob/master/erc20.lll)
99
if.lll, seq.lll, seq2.lll, when.lll - control flow tests *
1010
raw.lll - "raw" sequencing constrct from lll
1111
revert.lll - reverting a transaction
12-
weirdstring.lll - test lll string syntax
12+
lit.lll - test lll literals
1313

elle/tests/erc20.lll

Lines changed: 344 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,344 @@
1+
;;; ---------------------------------------------------------------------------
2+
;;; Implementation of an ERC20 Token contract in LLL
3+
;;;
4+
;;; Ben Edgington - ben@benjaminion.xyz
5+
;;;
6+
7+
(seq
8+
9+
;; --------------------------------------------------------------------------
10+
;; CONSTANTS
11+
12+
;; Token parameters.
13+
;; 0x40 is a "magic number" - the text of the string is placed here
14+
;; when returning the string to the caller. See return-string below.
15+
(def 'token-name-string (lit 0x40 "LLL Coin - love to code in LLL."))
16+
(def 'token-symbol-string (lit 0x40 "LLL"))
17+
(def 'token-decimals 0)
18+
(def 'token-supply 100) ; 100 total tokens
19+
20+
;; Booleans
21+
(def 'false 0)
22+
(def 'true 1)
23+
24+
;; Memory layout.
25+
(def 'mem-ret 0x00) ; Fixed due to compiler macro for return.
26+
(def 'mem-func 0x00) ; No conflict with mem-ret, so re-use.
27+
(def 'mem-keccak 0x00) ; No conflict with mem-func or mem-ret, so re-use.
28+
(def 'scratch0 0x20)
29+
(def 'scratch1 0x40)
30+
31+
;; Precomputed function IDs.
32+
(def 'get-name 0x06fdde03) ; name()
33+
(def 'get-symbol 0x95d89b41) ; symbol()
34+
(def 'get-decimals 0x313ce567) ; decimals()
35+
(def 'get-total-supply 0x18160ddd) ; totalSupply()
36+
(def 'get-balance-of 0x70a08231) ; balanceOf(address)
37+
(def 'transfer 0xa9059cbb) ; transfer(address,uint256)
38+
(def 'transfer-from 0x23b872dd) ; transferFrom(address,address,uint256)
39+
(def 'approve 0x095ea7b3) ; approve(address,uint256)
40+
(def 'get-allowance 0xdd62ed3e) ; allowance(address,address)
41+
42+
;; Event IDs
43+
(def 'transfer-event-id ; Transfer(address,address,uint256)
44+
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef)
45+
46+
(def 'approval-event-id ; Approval(address,address,uint256)
47+
0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925)
48+
49+
;; --------------------------------------------------------------------------
50+
;; UTILITIES
51+
52+
;; --------------------------------------------------------------------------
53+
;; The following define the key data-structures:
54+
;; - balance(addr) => value
55+
;; - allowance(addr,addr) => value
56+
57+
;; Balances are stored at s[owner_addr].
58+
(def 'balance (address) address)
59+
60+
;; Allowances are stored at s[owner_addr + keccak256(spender_addr)]
61+
;; We use a crypto function here to avoid any situation where
62+
;; approve(me, spender) can be abused to do approve(target, me).
63+
(def 'allowance (owner spender)
64+
(seq
65+
(mstore mem-keccak spender)
66+
(add owner (keccak256 mem-keccak 0x20))))
67+
68+
;; --------------------------------------------------------------------------
69+
;; For convenience we have macros to refer to function arguments
70+
71+
(def 'arg1 (calldataload 0x04))
72+
(def 'arg2 (calldataload 0x24))
73+
(def 'arg3 (calldataload 0x44))
74+
75+
;; --------------------------------------------------------------------------
76+
;; Revert is a soft return that does not consume the remaining gas.
77+
;; We use it when rejecting invalid user input.
78+
;;
79+
;; Note: The REVERT opcode will be implemented in Metropolis (EIP 140).
80+
;; Meanwhile it just causes an invalid instruction exception (similar
81+
;; to a "throw" in Solidity). When fully implemented, Revert could be
82+
;; use to return error codes, or even messages.
83+
84+
(def 'revert () (revert 0 0))
85+
86+
;; --------------------------------------------------------------------------
87+
;; Macro for returning string names.
88+
;; Compliant with the ABI format for strings.
89+
90+
(def 'return-string (string-literal)
91+
(seq
92+
(mstore 0x00 0x20) ; Points to our string's memory location
93+
(mstore 0x20 string-literal) ; Length. String itself is copied to 0x40.
94+
(return 0x00 (& (+ (mload 0x20) 0x5f) (~ 0x1f)))))
95+
; Round return up to 32 byte boundary
96+
97+
;; --------------------------------------------------------------------------
98+
;; Convenience macro for raising Events
99+
100+
(def 'event3 (id addr1 addr2 value)
101+
(seq
102+
(mstore scratch0 value)
103+
(log3 scratch0 0x20 id addr1 addr2)))
104+
105+
;; --------------------------------------------------------------------------
106+
;; Determines whether the stored function ID matches a known
107+
;; function hash and executes <code-body> if so.
108+
;; @param function-hash The four-byte hash of a known function signature.
109+
;; @param code-body The code to run in the case of a match.
110+
111+
(def 'function (function-hash code-body)
112+
(when (= (mload mem-func) function-hash)
113+
code-body))
114+
115+
;; --------------------------------------------------------------------------
116+
;; Gets the function ID and stores it in memory for reference.
117+
;; The function ID is in the leftmost four bytes of the call data.
118+
119+
(def 'uses-functions
120+
(seq
121+
(mstore mem-func 0)
122+
(calldatacopy (+ mem-func 28) 0x00 4)))
123+
124+
;; --------------------------------------------------------------------------
125+
;; GUARDS
126+
127+
;; --------------------------------------------------------------------------
128+
;; Checks that ensure that each function is called with the right
129+
;; number of arguments. For one thing this addresses the "ERC20
130+
;; short address attack". For another, it stops me making
131+
;; mistakes while testing. We use these only on the non-constant functions.
132+
133+
(def 'has-one-arg (unless (= 0x24 (calldatasize)) (revert)))
134+
(def 'has-two-args (unless (= 0x44 (calldatasize)) (revert)))
135+
(def 'has-three-args (unless (= 0x64 (calldatasize)) (revert)))
136+
137+
;; --------------------------------------------------------------------------
138+
;; Check that addresses have only 160 bits and revert if not.
139+
;; We use these input type-checks on the non-constant functions.
140+
141+
(def 'is-address (addr)
142+
(when
143+
(shr addr 160)
144+
(revert)))
145+
146+
;; --------------------------------------------------------------------------
147+
;; Check that transfer values are smaller than total supply and
148+
;; revert if not. This should effectively exclude negative values.
149+
150+
(def 'is-value (value)
151+
(when (> value token-supply) (revert)))
152+
153+
;; --------------------------------------------------------------------------
154+
;; Will revert if sent any Ether. We use the macro immediately so as
155+
;; to abort if sent any Ether during contract deployment.
156+
157+
(def 'not-payable
158+
(when (callvalue) (revert)))
159+
160+
not-payable
161+
162+
;; --------------------------------------------------------------------------
163+
;; INITIALISATION
164+
;;
165+
;; Assign all tokens initially to the owner of the contract.
166+
167+
(sstore (balance (caller)) token-supply)
168+
169+
;; --------------------------------------------------------------------------
170+
;; CONTRACT CODE
171+
172+
(returnlll
173+
(seq not-payable uses-functions
174+
175+
;; ----------------------------------------------------------------------
176+
;; Getter for the name of the token.
177+
;; @abi name() constant returns (string)
178+
;; @return The token name as a string.
179+
180+
(function get-name
181+
(return-string token-name-string))
182+
183+
;; ----------------------------------------------------------------------
184+
;; Getter for the symbol of the token.
185+
;; @abi symbol() constant returns (string)
186+
;; @return The token symbol as a string.
187+
188+
(function get-symbol
189+
(return-string token-symbol-string))
190+
191+
;; ----------------------------------------------------------------------
192+
;; Getter for the number of decimals assigned to the token.
193+
;; @abi decimals() constant returns (uint256)
194+
;; @return The token decimals.
195+
196+
(function get-decimals
197+
(return token-decimals))
198+
199+
;; ----------------------------------------------------------------------
200+
;; Getter for the total token supply.
201+
;; @abi totalSupply() constant returns (uint256)
202+
;; @return The token supply.
203+
204+
(function get-total-supply
205+
(return token-supply))
206+
207+
;; ----------------------------------------------------------------------
208+
;; Returns the account balance of another account.
209+
;; @abi balanceOf(address) constant returns (uint256)
210+
;; @param owner The address of the account's owner.
211+
;; @return The account balance.
212+
213+
(function get-balance-of
214+
(seq
215+
216+
(def 'owner arg1)
217+
218+
(return (sload (balance owner)))))
219+
220+
;; ----------------------------------------------------------------------
221+
;; Transfers _value amount of tokens to address _to. The command
222+
;; should throw if the _from account balance has not enough
223+
;; tokens to spend.
224+
;; @abi transfer(address, uint256) returns (bool)
225+
;; @param to The account to receive the tokens.
226+
;; @param value The quantity of tokens to transfer.
227+
;; @return Success (true). Other outcomes result in a Revert.
228+
229+
(function transfer
230+
(seq has-two-args (is-address arg1) (is-value arg2)
231+
232+
(def 'to arg1)
233+
(def 'value arg2)
234+
235+
(when value ; value == 0 is a no-op
236+
(seq
237+
238+
;; The caller's balance. Save in memory for efficiency.
239+
(mstore scratch0 (sload (balance (caller))))
240+
241+
;; Revert if the caller's balance is not sufficient.
242+
(when (> value (mload scratch0))
243+
(revert))
244+
245+
;; Make the transfer
246+
;; It would be good to check invariants (sum of balances).
247+
(sstore (balance (caller)) (- (mload scratch0) value))
248+
(sstore (balance to) (+ (sload (balance to)) value))
249+
250+
;; Event - Transfer(address,address,uint256)
251+
(event3 transfer-event-id (caller) to value)))
252+
253+
(return true)))
254+
255+
;; ----------------------------------------------------------------------
256+
;; Send _value amount of tokens from address _from to address _to
257+
;; @abi transferFrom(address,address,uint256) returns (bool)
258+
;; @param from The account to send the tokens from.
259+
;; @param to The account to receive the tokens.
260+
;; @param value The quantity of tokens to transfer.
261+
;; @return Success (true). Other outcomes result in a Revert.
262+
263+
(function transfer-from
264+
(seq has-three-args (is-address arg1) (is-address arg2) (is-value arg3)
265+
266+
(def 'from arg1)
267+
(def 'to arg2)
268+
(def 'value arg3)
269+
270+
(when value ; value == 0 is a no-op
271+
272+
(seq
273+
274+
;; Save data to memory for efficiency.
275+
(mstore scratch0 (sload (balance from)))
276+
(mstore scratch1 (sload (allowance from (caller))))
277+
278+
;; Revert if not enough funds, or not enough approved.
279+
(when
280+
(||
281+
(> value (mload scratch0))
282+
(> value (mload scratch1)))
283+
(revert))
284+
285+
;; Make the transfer and update allowance.
286+
(sstore (balance from) (- (mload scratch0) value))
287+
(sstore (balance to) (+ (sload (balance to)) value))
288+
(sstore (allowance from (caller)) (- (mload scratch1) value))
289+
290+
;; Event - Transfer(address,address,uint256)
291+
(event3 transfer-event-id from to value)))
292+
293+
(return true)))
294+
295+
;; ----------------------------------------------------------------------
296+
;; Allows _spender to withdraw from your account multiple times,
297+
;; up to the _value amount. If this function is called again it
298+
;; overwrites the current allowance with _value.
299+
;; @abi approve(address,uint256) returns (bool)
300+
;; @param spender The withdrawing account having its limit set.
301+
;; @param value The maximum allowed amount.
302+
;; @return Success (true). Other outcomes result in a Revert.
303+
304+
(function approve
305+
(seq has-two-args (is-address arg1) (is-value arg2)
306+
307+
(def 'spender arg1)
308+
(def 'value arg2)
309+
310+
;; Force users set the allowance to 0 before setting it to
311+
;; another value for the same spender. Prevents this attack:
312+
;; https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM
313+
(when
314+
(&& value (sload (allowance (caller) spender)))
315+
(revert))
316+
317+
(sstore (allowance (caller) spender) value)
318+
319+
;; Event - Approval(address,address,uint256)
320+
(event3 approval-event-id (caller) spender value)
321+
322+
(return true)))
323+
324+
;; ----------------------------------------------------------------------
325+
;; Returns the amount which _spender is still allowed to withdraw
326+
;; from _owner.
327+
;; @abi allowance(address,address) constant returns (uint256)
328+
;; @param owner The owning account.
329+
;; @param spender The withdrawing account.
330+
;; @return The allowed amount remaining.
331+
332+
(function get-allowance
333+
(seq
334+
335+
(def 'owner arg1)
336+
(def 'spender arg2)
337+
338+
(return (sload (allowance owner spender)))))
339+
340+
;; ----------------------------------------------------------------------
341+
;; Fallback: No functions matched the function ID provided.
342+
343+
(revert)))
344+
)

elle/tests/weirdstring.lll

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)