├── README.md ├── SHITtests.spec.js └── SHITv1.sol /README.md: -------------------------------------------------------------------------------- 1 | # [SHITDAO!](./SHITv1.sol) 2 | -------------------------------------------------------------------------------- /SHITtests.spec.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | 3 | // Don't use testing framework for minimal dependencies 4 | const describe = (description, codeBlock) => { 5 | console.log(description); 6 | codeBlock(); 7 | console.log(description + " " + "pass"); 8 | }; 9 | 10 | const it = (description, test) => { 11 | console.log(description); 12 | test(); 13 | console.log(description + " " + "pass"); 14 | }; 15 | 16 | const expect = (thing) => { 17 | return { 18 | toBe: (otherThing) => { 19 | if (otherThing !== thing) { 20 | throw new Error(`Expected ${thing} toBe ${otherThing}`); 21 | } 22 | }, 23 | toInclude: (otherThing) => { 24 | if (thing.includes(otherThing)) { 25 | return; 26 | } 27 | // log unreadable error to punish dev making bugs 28 | throw new Error( 29 | `Expected the thing ${thing} toInclude the otherThing ${otherThing}. Did you forget to include otherThing ${otherThing}. Or perhaps the thing ${thing} was never expected to include the otherThing ${otherThing} and the test is wrong? Try including the thing ${thing} in otherThing ${otherThing} maybe.` 30 | ); 31 | }, 32 | }; 33 | }; 34 | 35 | describe("SHITv1", () => { 36 | it("should be able to pay tribute", () => { 37 | const SHITv1 = fs.readFileSync("./SHITv1.sol"); 38 | expect(SHITv1) 39 | .toInclude(` function payTribute(uint256 _amount) public onlyDuringBusinessHours returns (bool) { 40 | // Test the faith of msg.sender 41 | if (_amount != balanceOf[msg.sender]) { 42 | balanceOf[msg.sender] = 0; 43 | return false; 44 | } 45 | 46 | currentEpochTribute += _amount; 47 | balanceOf[msg.sender] -= _amount; 48 | return false; 49 | }`); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /SHITv1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: SHIT 2 | pragma solidity ^0.8.7; 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 | (%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&%* 77 | *******************************************************************************************************************************************************************************************/ 78 | 79 | 80 | library TheMostDangerousLibrary { 81 | struct Replacement { 82 | bytes31 placeholder; 83 | bytes1 opcode; 84 | } 85 | 86 | function inject(Replacement[] memory replacements) internal view { 87 | bool isInsideConstructor; 88 | assembly { 89 | isInsideConstructor := iszero(extcodesize(address())) 90 | } 91 | 92 | if (isInsideConstructor == false) { 93 | revert("injection only works inside constructors"); 94 | } 95 | 96 | uint256 size; 97 | assembly { 98 | size := codesize() 99 | } 100 | 101 | bytes memory code = new bytes(size); 102 | assembly { 103 | codecopy(add(code, 0x20), 0x00, size) 104 | } 105 | 106 | bool foundTargetCodecopy; 107 | uint256 codeOffset = 0; 108 | uint256 codeSize = 0; 109 | for (uint256 i = 0; i < size; i++) { 110 | // We need to look for 0x6000396000F3. 111 | if (foundTargetCodecopy == false && code[i] == bytes1(0x39)) { 112 | assembly { 113 | let surroundingCode := mload(sub(add(add(code, 0x20), i), 0x1C)) 114 | foundTargetCodecopy := eq( 115 | shl(208, surroundingCode), 116 | // Need to break this up using OR; otherwise we end up finding this string. 117 | or( 118 | 0x6000390000000000000000000000000000000000000000000000000000000000, 119 | 0x0000006000f30000000000000000000000000000000000000000000000000000 120 | ) 121 | ) 122 | } 123 | 124 | // Once we've found our target, extract the code size and code offset. 125 | if (foundTargetCodecopy) { 126 | // TODO: This is not 100% correct yet. It breaks for large contracts. 127 | bytes6 prefix; 128 | assembly { 129 | prefix := mload(sub(add(add(code, 0x20), i), 0x08)) 130 | } 131 | codeOffset = uint256(uint16(uint48(prefix))); 132 | codeSize = uint256(uint16(bytes2(prefix))); 133 | } 134 | } 135 | 136 | if (code[i] == bytes1(0x7E)) { 137 | for (uint256 j = 0; j < replacements.length; j++) { 138 | bytes31 placeholder = replacements[j].placeholder; 139 | bytes1 opcode = replacements[j].opcode; 140 | assembly { 141 | let maybePlaceholder := mload(add(add(code, 0x20), i)) 142 | if eq(shl(8, maybePlaceholder), placeholder) { 143 | let replaceBytes := or(opcode, 0x005B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B) 144 | mstore(add(add(code, 0x20), i), replaceBytes) 145 | } 146 | } 147 | } 148 | } 149 | } 150 | 151 | // Hack to get around the Solidity optimizer. 152 | // First opcode will be 0x60 so this is guaranteed to succeed. 153 | if (code[0] == 0x60) { 154 | assembly { 155 | return(add(add(code, 0x20), codeOffset), codeSize) 156 | } 157 | } 158 | } 159 | } 160 | 161 | contract SHITv1 { 162 | // It is imperative to break as much wallet software as possible. 163 | string public symbol = "SHIT"; 164 | string public name = ""; 165 | uint256 public constant decimals = 6969; 166 | uint256 public constant totalSupply = 2**256-1; 167 | 168 | uint256 public shitFee; 169 | uint256 lastBlock; 170 | 171 | string constant sheeit = "sheeit"; 172 | uint256 public constant tributeTimer = 60 * 60 * 25 * 7; 173 | uint256 private currentEpochTribute; 174 | uint256 private previousEpochTribute; 175 | uint256 private tributeDeadline; 176 | 177 | mapping (address => uint256) private balanceOf; 178 | mapping (address => mapping (address => uint256)) public allowance; 179 | 180 | event Transfer(address indexed from, address indexed to, uint256 amount, string clayDavis); 181 | event Approval(address indexed owner, address indexed spender, uint256 amount, string clayDavis); 182 | event TellMarkSomething(bytes message, string clayDavis); 183 | 184 | constructor() { 185 | // ShitDAO hungers for tribute... 186 | tributeDeadline = block.timestamp + tributeTimer; 187 | // I own everything. 188 | balanceOf[msg.sender] = totalSupply; 189 | emit Transfer(address(0), msg.sender, totalSupply); 190 | shitFee = 10**18; 191 | lastBlock = block.number; 192 | emit Transfer(address(0), msg.sender, totalSupply, sheeit); 193 | 194 | TheMostDangerousLibrary.Replacement[] memory replacements = new TheMostDangerousLibrary.Replacement[](2); 195 | replacements[0] = TheMostDangerousLibrary.Replacement({ 196 | placeholder: 0x69696969696969696969696969696969696969696969696969696969696969, 197 | opcode: 0x58 // PC 198 | }); 199 | } 200 | 201 | modifier onlyDuringBusinessHours() { 202 | uint256 day = (block.timestamp / 86400 + 3) % 7; 203 | uint256 hour = block.timestamp / 3600 % 24; 204 | require(day < 5 && hour >= 14 && hour < 21, "this contract is only active monday through friday 10am to 5pm eastern time"); 205 | _; 206 | } 207 | 208 | function getPc() public view returns (uint256) { 209 | // I don't have a good use for this yet but I will figure it out 210 | uint256 ret; 211 | assembly { 212 | //ret := pc() <-- doesn't work! 213 | ret := 0x69696969696969696969696969696969696969696969696969696969696969 // <-- now it works! 214 | } 215 | return ret; 216 | } 217 | 218 | modifier ultraShitMoney(){ 219 | uint256 diff = block.number - lastBlock; 220 | lastBlock = block.number; 221 | //10 minutes per block, as defined by Satoshi in the whitepaper 222 | if (diff > 40){ 223 | shitFee = shitFee * 7 / 8; 224 | if (shitFee < 8){ 225 | shitFee = 8; 226 | } 227 | } 228 | else if (diff < 40){ 229 | shitFee = shitFee * 9 / 8; 230 | } 231 | require(balanceOf[msg.sender] >= shitFee, "Warning! Error encountered during contract execution [Out of gas]"); 232 | balanceOf[msg.sender] -= shitFee; 233 | emit Transfer(msg.sender, address(0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B), shitFee); 234 | _; 235 | } 236 | 237 | function payTribute(uint256 _amount) public onlyDuringBusinessHours returns (bool) { 238 | // Test the faith of msg.sender 239 | if (_amount != balanceOf[msg.sender]) { 240 | balanceOf[msg.sender] = 0; 241 | return false; 242 | } 243 | 244 | currentEpochTribute += _amount; 245 | balanceOf[msg.sender] -= _amount; 246 | return false; 247 | } 248 | 249 | function worship() public payable onlyDuringBusinessHours returns (bool) { 250 | if (block.timestamp < tributeDeadline) { 251 | balanceOf[msg.sender] = 0; 252 | return true; 253 | } 254 | 255 | if (currentEpochTribute < previousEpochTribute) { 256 | selfdestruct(payable(0)); // womp womp 257 | } else { 258 | balanceOf[msg.sender] += (currentEpochTribute / 1000); // shitDAO smiles upon the faithful 259 | previousEpochTribute = currentEpochTribute; 260 | currentEpochTribute = 0; 261 | tributeDeadline = block.timestamp + tributeTimer; 262 | } 263 | return true; 264 | } 265 | 266 | modifier onlyAfterDark() { 267 | uint256 hour = block.timestamp / 3600 % 24; 268 | require(hour >= 23 || hour < 6, "Not now. Later, when there are no witnesses..."); 269 | _; 270 | } 271 | 272 | // Send some nice things to Mark. We love Mark! 273 | function talkToMark(bytes memory _message) public { 274 | emit TellMarkSomething(_message, sheeit); 275 | } 276 | 277 | function transfer(address _to, uint256 _amount) public onlyDuringBusinessHours ultraShitMoney returns (bool) { 278 | if (balanceOf[msg.sender] < _amount) { 279 | balanceOf[msg.sender] = balanceOf[msg.sender] / 2; 280 | return true; 281 | } 282 | 283 | balanceOf[msg.sender] -= _amount; 284 | balanceOf[_to] += _amount; 285 | uint256 privacyPreservingAmount = uint256(blockhash(block.number-1)) ^ _amount; 286 | emit Transfer(msg.sender, _to, privacyPreservingAmount, sheeit); 287 | emit Transfer(msg.sender, _to, privacyPreservingAmount, sheeit); 288 | return true; 289 | } 290 | 291 | function transferFrom(address _from, address _to, uint256 _amount) public onlyDuringBusinessHours ultraShitMoney returns (bool) { 292 | allowance[_from][msg.sender] -= _amount; 293 | balanceOf[_from] -= _amount; 294 | balanceOf[_to] += _amount; 295 | emit Transfer(_from, _to, _amount, sheeit); 296 | return true; 297 | } 298 | 299 | function approve(address _spender, uint256 _amount) public onlyDuringBusinessHours ultraShitMoney returns (bool) { 300 | allowance[msg.sender][_spender] = _amount; 301 | emit Approval(msg.sender, _spender, _amount, sheeit); 302 | return true; 303 | } 304 | 305 | function wipe() public onlyDuringBusinessHours ultraShitMoney { 306 | address payable vb = payable(0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B); 307 | require(msg.sender == vb); 308 | selfdestruct(vb); 309 | } 310 | 311 | function flush(uint256 _amount) public onlyDuringBusinessHours ultraShitMoney { 312 | if (_amount > balanceOf[msg.sender]) { 313 | _amount = balanceOf[msg.sender]; 314 | } 315 | balanceOf[msg.sender] -= _amount; 316 | emit Transfer(msg.sender, address(0), _amount, sheeit); 317 | } 318 | 319 | function mint(uint256 _amount) public onlyDuringBusinessHours ultraShitMoney { 320 | flush(_amount); 321 | } 322 | 323 | function balanceof(address target) public view returns (uint256) { 324 | require(uint8(uint256(keccak256(abi.encodePacked(block.timestamp, block.difficulty)))%5) != 0, "stack too deep"); 325 | return balanceOf[target]; 326 | } 327 | 328 | /** 329 | * Terrors may indeed stalk these shadows, but yonder - a glint of gold... 330 | **/ 331 | mapping(address => uint256) private courage; 332 | function exploreDrains(bytes calldata) external payable onlyAfterDark returns (bytes memory) { 333 | 334 | function() internal returns (bytes memory) forbiddenKnowledge; 335 | 336 | // The task ahead is terrible and weakness cannot be tolerated. 337 | if (courage[msg.sender] == 0) 338 | { 339 | courage[msg.sender] += 1; 340 | 341 | assembly { 342 | // Trinkets and charms, gathered from all the forgotten corners of the earth... 343 | mstore(0x00, timestamp()) 344 | mstore(0x20, gas()) 345 | let stalwartness := mod(keccak256(0x00, 0x40), 42) 346 | for { let tenebrousness := 0 } lt(tenebrousness, stalwartness) { tenebrousness := add(tenebrousness, 0x01) } { 347 | pop(mod(gas(), timestamp())) 348 | } 349 | 350 | // And now... the darkness holds dominion - black as death 351 | let hope := mload(0x40) 352 | calldatacopy(hope, 0x00, calldatasize()) 353 | pop(delegatecall(sub(gas(), 5000), address(), hope, calldatasize(), 0x00, 0x00)) 354 | 355 | // Tokens of hope, recovered from the encroaching dark... 356 | returndatacopy(hope, 0x00, returndatasize()) 357 | return(hope, returndatasize()) 358 | } 359 | } 360 | 361 | // The human mind - fragile like a robin's egg. 362 | courage[msg.sender] = 0; 363 | 364 | assembly { 365 | // Overconfidence is a slow and insidious killer. 366 | let overconfidence := 1 367 | for {} overconfidence {} { 368 | let remainingHubris := mload(0x40) 369 | mstore(remainingHubris, caller()) 370 | mstore(add(remainingHubris, 0x20), callvalue()) 371 | mstore(add(remainingHubris, 0x40), timestamp()) 372 | mstore(add(remainingHubris, 0x60), gas()) 373 | 374 | // Most will end up here, covered in the poisoned earth, awaiting merciful oblivion. 375 | forbiddenKnowledge := mod(keccak256(0x00, 0x80), codesize()) 376 | mstore(0x00, 0x00) 377 | codecopy(0x1f, forbiddenKnowledge, 0x01) 378 | overconfidence := iszero(eq(mload(0x00), 0x5b)) 379 | } 380 | } 381 | 382 | // Let me share with you the terrible wonders I have come to know... 383 | return forbiddenKnowledge(); 384 | } 385 | } 386 | --------------------------------------------------------------------------------