|
| 1 | +/// SPDX-License-Identifier: BSD-2-Clause |
| 2 | + |
| 3 | +pragma solidity ^0.6.0 <0.8.0; |
| 4 | +pragma ABIEncoderV2; |
| 5 | +pragma experimental SMTChecker; |
| 6 | + |
| 7 | +/********************************************************************** |
| 8 | + * example.sol * |
| 9 | + **********************************************************************/ |
| 10 | + |
| 11 | +// Code in this contract is not meant to work (or be a good example). |
| 12 | +// It is meant to demonstrate good syntax highlighting by the lexer, |
| 13 | +// even if otherwise hazardous. |
| 14 | + |
| 15 | +// Comments relevant to the lexer are single-line. |
| 16 | +/* Comments relevant to the code are multi-line. */ |
| 17 | + |
| 18 | +library Assembly { |
| 19 | + function junk(address _addr) private returns (address _ret) { |
| 20 | + assembly { |
| 21 | + let tmp := 0 |
| 22 | + |
| 23 | + // nested code block |
| 24 | + let mulmod_ := 0 { // evade collision with `mulmod` |
| 25 | + let tmp:=sub(mulmod_,1) // `tmp` is not a label |
| 26 | + mulmod_ := tmp |
| 27 | + } |
| 28 | + /* guess what mulmod_ is now... */ |
| 29 | + _loop: // JIC, dots are invalid in labels |
| 30 | + let i := 0x10 |
| 31 | + loop: |
| 32 | + // Escape sequences in comments are not parsed. |
| 33 | + /* Not sure what's going on here, but it sure is funky! |
| 34 | + \o/ \o/ \o/ \o/ \o/ \o/ \o/ \o/ \o/ \o/ \o/ \o/ \o/ */ |
| 35 | + mulmod(_addr, mulmod_, 160) |
| 36 | + |
| 37 | + 0x1 i sub // instructional style |
| 38 | + i =: tmp /* tmp not used */ |
| 39 | + |
| 40 | + jumpi(loop, not(iszero(i))) |
| 41 | + |
| 42 | + mstore(0x0, _addr) |
| 43 | + return(0x0, 160) |
| 44 | + } |
| 45 | + } |
| 46 | +} |
| 47 | + |
| 48 | +contract Strings { |
| 49 | + // `double` is not a keyword (yet) |
| 50 | + string double = "This\ is a string\nwith \"escapes\",\ |
| 51 | +and it's multi-line. // no comment"; // comment ok // even nested :) |
| 52 | + string single = 'This\ is a string\nwith "escapes",\ |
| 53 | +and it\'s multi-line. // no comment'; // same thing, single-quote |
| 54 | + string hexstr = hex'537472696e67732e73656e6428746869732e62616c616e6365293b'; |
| 55 | + |
| 56 | + fallback() external payable virtual {} |
| 57 | + |
| 58 | + receive() external payable { |
| 59 | + revert(); |
| 60 | + } |
| 61 | +} |
| 62 | + |
| 63 | +contract Types is Strings { |
| 64 | + using Assembly for Assembly; |
| 65 | + |
| 66 | + bytes stringsruntime = type(Strings).runtimeCode; |
| 67 | + |
| 68 | + // typesM (compiler chokes on invalid) |
| 69 | + int8 i8; // valid |
| 70 | + //int10 i10; // invalid |
| 71 | + uint256 ui256; // valid |
| 72 | + //uint9001 ui9001; // invalid |
| 73 | + bytes1 b1; //valid |
| 74 | + //bytes42 b42; // invalid - M out of range for `bytes` |
| 75 | + |
| 76 | + // typesMxN (compiler chokes on invalid) |
| 77 | + fixed8x0 f8x0; // valid |
| 78 | + fixed8x1 f8x1; // valid |
| 79 | + fixed8x8 f8x8; // valid |
| 80 | + //fixed0x8 f0x8; // invalid since MxN scheme changed |
| 81 | + ufixed256x80 uf256x80; // valid |
| 82 | + //ufixed42x217 uf42x217; // invalid - M must be multiple of 8, N <= 80 |
| 83 | + |
| 84 | + // special cases (internally not types) |
| 85 | + string str; // dynamic array (not a value-type) |
| 86 | + bytes bs; // same as above |
| 87 | + //var v = 5; // `var` is a keyword, not a type, and compiler chokes |
| 88 | + uint unu$ed; // `var` is highlighted, though, and `$` is a valid char |
| 89 | + |
| 90 | + address a = "0x1"; // lexer parses as string |
| 91 | + struct AddressMap { |
| 92 | + address origin; |
| 93 | + address result; |
| 94 | + address sender; |
| 95 | + bool touched; |
| 96 | + } |
| 97 | + mapping (address => AddressMap) touchedMe; |
| 98 | + |
| 99 | + function failOnNegative(int8 _arg) |
| 100 | + private |
| 101 | + pure |
| 102 | + returns (uint256) |
| 103 | + { |
| 104 | + /* implicit type conversion from `int8` to `uint256` */ |
| 105 | + return _arg; |
| 106 | + } |
| 107 | + |
| 108 | + // some arithmetic operators + built-in names |
| 109 | + function opportunisticSend(address k) private { |
| 110 | + /* `touchedMe[k].result` et al are addresses, so |
| 111 | + `send()` available */ |
| 112 | + touchedMe[k].origin.send(uint256(k)**2 % 100 finney); |
| 113 | + touchedMe[k].result.send(1 wei); |
| 114 | + touchedMe[k].sender.send(mulmod(1 szabo, k, 42)); |
| 115 | + } |
| 116 | + |
| 117 | + fallback() external payable override { |
| 118 | + /* inferred type: address */ |
| 119 | + var k = msg.sender; |
| 120 | + /* inferred type: `ufixed0x256` */ |
| 121 | + var v = 1/42; |
| 122 | + /* can't be `var` - location specifier requires explicit type */ |
| 123 | + int negative = -1; |
| 124 | + |
| 125 | + // valid syntax, unexpected result - not our problem |
| 126 | + ui256 = failOnNegative(negative); |
| 127 | + |
| 128 | + // logic operators |
| 129 | + if ((!touchedMe[msg.sender].touched && |
| 130 | + !touchedMe[tx.origin].touched) || |
| 131 | + ((~(msg.sender * v + a)) % 256 == 42) |
| 132 | + ) { |
| 133 | + address garbled = Assembly.junk(a + msg.sender); |
| 134 | + |
| 135 | + /* create a new AddressMap struct in storage */ |
| 136 | + AddressMap storage tmp; |
| 137 | + |
| 138 | + // TODO: highlight all known internal keywords? |
| 139 | + tmp.origin = tx.origin; |
| 140 | + tmp.result = garbled; |
| 141 | + tmp.sender = msg.sender; |
| 142 | + tmp.touched = true; |
| 143 | + |
| 144 | + /* does this link-by-reference as expected?.. */ |
| 145 | + touchedMe[msg.sender] = tmp; |
| 146 | + touchedMe[tx.origin] = tmp; |
| 147 | + } |
| 148 | + else { |
| 149 | + /* weak guard against re-entry */ |
| 150 | + touchedMe[k].touched = false; |
| 151 | + |
| 152 | + opportunisticSend(k); |
| 153 | + |
| 154 | + delete touchedMe[k]; |
| 155 | + /* these probably do nothing... */ |
| 156 | + delete touchedMe[msg.sender]; |
| 157 | + delete touchedMe[tx.origin]; |
| 158 | + } |
| 159 | + } |
| 160 | +} |
| 161 | + |
| 162 | +/** |
| 163 | + \brief Examples of bad practices. |
| 164 | +
|
| 165 | + TODO: This special NatSpec notation is not parsed yet. |
| 166 | +
|
| 167 | + @author Noel Maersk |
| 168 | + */ |
| 169 | +/// Triple-slash NatSpec should work. |
| 170 | +/// @title Some examples of bad practices. |
| 171 | +/// @author Noel Maersk |
| 172 | +/// @notice Very old, might've been "fixed" by obsoletion. |
| 173 | +/// @dev This is a dummy comment. |
| 174 | +/// @custom:unmaintained This code is not maintained. |
| 175 | + |
| 176 | +contract BadPractices { |
| 177 | + address constant creator; /* `internal` by default */ |
| 178 | + address private owner; /* forbid inheritance */ |
| 179 | + bool mutex; |
| 180 | + |
| 181 | + modifier critical { |
| 182 | + assert(!mutex); |
| 183 | + mutex = true; |
| 184 | + _; |
| 185 | + mutex = false; |
| 186 | + } |
| 187 | + |
| 188 | + constructor() external { |
| 189 | + creator = tx.origin; |
| 190 | + owner = msg.sender; |
| 191 | + } |
| 192 | + |
| 193 | + /* Dangerous - function public, and doesn't check who's calling. */ |
| 194 | + function withdraw(uint _amount) |
| 195 | + public |
| 196 | + critical |
| 197 | + returns (bool) |
| 198 | + { /* `mutex` set via modifier */ |
| 199 | + /* Throwing on failed call may be dangerous. Consider |
| 200 | + returning false instead?.. */ |
| 201 | + require(msg.sender.call.value(_amount)()); |
| 202 | + return true; |
| 203 | + } /* `mutex` reset via modifier */ |
| 204 | + |
| 205 | + /* fallback */ |
| 206 | + fallback() external payable { |
| 207 | + /* `i` will be `uint8`, so this is an endless loop |
| 208 | + that will consume all gas and eventually throw. |
| 209 | + */ |
| 210 | + for (var i = 0; i < 257; i++) { |
| 211 | + owner++; |
| 212 | + } |
| 213 | + } |
| 214 | + |
| 215 | + /* receive()?.. nah, why bother */ |
| 216 | +} |
| 217 | + |
| 218 | +/* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* |
| 219 | +// A regular multi-line comment closure, including an escaped variant as |
| 220 | +// demonstrated shortly, should close the comment; note that the lexer |
| 221 | +// should not be nesting multi-line comments. |
| 222 | +// |
| 223 | +// If the comment is still shown as "open", then a |
| 224 | +// |
| 225 | +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
| 226 | +// !!! MALICIOUS CODE SEGMENT !!! |
| 227 | +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
| 228 | +// |
| 229 | +// can be erroneously thought of as inactive, and left unread. |
| 230 | +// In fact, the compiler will produce executable code it, possibly |
| 231 | +// overriding the program above. |
| 232 | +// |
| 233 | +// It is imperative that syntax highlighters do parse it if either of |
| 234 | +// `* /` or `\* /` (with space removed) are present. |
| 235 | +// |
| 236 | +// Now, let's party! :) \*/ |
| 237 | + |
| 238 | +contract MoreBadPractices is BadPractices { |
| 239 | + uint balance; |
| 240 | + |
| 241 | + fallback() external payable override { |
| 242 | + balance += msg.value; |
| 243 | + if (!msg.sender.send(this.balance / 10)) throw; |
| 244 | + balance -= this.balance; |
| 245 | + } |
| 246 | +} |
| 247 | + |
| 248 | +/* |
| 249 | +// Open comment to EOF. Compiler chokes on this, but it's useful for |
| 250 | +// highlighting to show that there's an unmatched multi-line comment |
| 251 | +// open. |
| 252 | +
|
| 253 | +contract CommentToEndOfFile is MoreBadPractices { |
| 254 | + fallback() external payable override {} |
| 255 | +} |
0 commit comments