├── .prettierrc.js ├── .shellcheckrc ├── .vscode └── ltex.dictionary.en-US.txt ├── LICENSE.txt ├── README.md ├── justfile ├── package.json ├── scripts ├── common.sh ├── contract-size.sh ├── deploy.sh ├── estimate-gas.sh ├── helper-config.sh ├── run-temp-testnet.sh └── test-deploy.sh └── src ├── ACL └── Trust.sol ├── AbiDecodeTest.sol ├── AccountWatcher.sol ├── AllowancesHelper.sol ├── Approvals.sol ├── BalanceScanner.sol ├── BalancesAndAllowancesHelper.sol ├── BytesParsing.sol ├── CallFunctionWithoutContract.sol ├── CalldataUtils.lib.sol ├── CodeHashCache.sol ├── CounterfactualFactory.sol ├── ERC20InvalidMock.sol ├── ERC20Mock.sol ├── ERCQuery.sol ├── EthHelper.sol ├── GasMeterFactory.sol ├── GenericFactory.sol ├── Helpers.sol ├── ImmutableCreate2Factory.sol ├── Introspection.sol ├── MeterMaid.sol ├── PairsHelper.sol ├── PhonyUser.sol ├── ReplayProtection.sol ├── SelectorsAndSignatures.sol ├── TokenMetadata.sol ├── UniswapV3 ├── FixedMath.sol ├── MockUniSwapRouterV3.sol └── MockUniV3Pool.sol ├── WalletSummarizer.sol ├── getInterface.sol ├── test ├── TestUtils.sol └── oops.lib.sol └── utils ├── Create.sol └── errors.sol /.prettierrc.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Prettier configuration for Solidity 3 | * @version 1.3.1 4 | * @summary base config adapted from AirBNB to reduce diff churn 5 | * @overrides solidity settings from Solidity Documentation 6 | * @note `printWidth` is not a line character capture 7 | * @dev `explicitTypes` 8 | * @solidity versions ^0.8.0 bytes1 9 | */ 10 | 11 | 'use strict'; 12 | 13 | module.exports = { 14 | arrowParens: 'always', 15 | bracketSpacing: true, 16 | endOfLine: 'lf', 17 | printWidth: 80, 18 | singleQuote: true, 19 | tabWidth: 2, 20 | trailingComma: 'all', 21 | quoteProps: 'as-needed', 22 | semi: true, 23 | overrides: [ 24 | { 25 | files: '*.sol', 26 | options: { 27 | printWidth: 100, 28 | tabWidth: 4, 29 | useTabs: false, 30 | singleQuote: false, 31 | bracketSpacing: true, 32 | explicitTypes: 'always', 33 | }, 34 | }, 35 | ], 36 | }; 37 | /** @exports prettier-config-solidity */ 38 | -------------------------------------------------------------------------------- /.shellcheckrc: -------------------------------------------------------------------------------- 1 | shell=bash 2 | enable=deprecate-which 3 | enable=require-double-brackets 4 | disable=SC1090 # sourcing files; ENV SHELLCHECK_OPTS='--shell=bash --exclude=SC1090' 5 | disable=SC2034 # for localizing variables set in called functions 6 | -------------------------------------------------------------------------------- /.vscode/ltex.dictionary.en-US.txt: -------------------------------------------------------------------------------- 1 | SPDX-License-Identifier 2 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2021 CommodityStream LLC 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## [isdx](#) 2 | > Introspection / Observability smart contracts 3 | 4 | ### examples 5 | 6 | - `AllowancesHelper` 7 | 8 | ```solidity 9 | // Fetch allowances 10 | Allowance[] memory _allowances = new Allowance[](numberOfAllowances); 11 | uint256 allowanceIdx; 12 | for (tokenIdx = 0; tokenIdx < tokensAddresses.length; tokenIdx++) { 13 | for (spenderIdx = 0; spenderIdx < spenderAddresses.length; spenderIdx++) { 14 | address spenderAddress = spenderAddresses[spenderIdx]; 15 | address tokenAddress = tokensAddresses[tokenIdx]; 16 | IERC20 token = IERC20(tokenAddress); 17 | uint256 amount = token.allowance(ownerAddress, spenderAddress); 18 | if (amount > 0) { 19 | Allowance memory allowance = Allowance({ 20 | owner: ownerAddress, 21 | spender: spenderAddress, 22 | amount: amount, 23 | token: tokenAddress 24 | }); 25 | _allowances[allowanceIdx] = allowance; 26 | allowanceIdx++; 27 | } 28 | } 29 | } 30 | return _allowances; 31 | ``` 32 | -------------------------------------------------------------------------------- /justfile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env just --justfile 2 | 3 | alias t := test 4 | 5 | alias c := check 6 | 7 | bt := '0' 8 | 9 | export RUST_BACKTRACE := bt 10 | 11 | log := "warn" 12 | 13 | export JUST_LOG := log 14 | 15 | test: 16 | forge test 17 | 18 | build: 19 | forge build --root . 20 | 21 | run: 22 | forge run 23 | 24 | install: 25 | forge install 26 | 27 | check: 28 | forge test -f $ETH_RPC_URL -vvv 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vzor", 3 | "version": "0.0.0", 4 | "description": "I can see the Earth through the \"VZOR\" (porthole). The Earth is clearly visible", 5 | "scripts": { 6 | "fmt": "npx prettier --config .prettierrc.js --write '**/*.{sol,ts,tsx,js,md,yml,yaml}'" 7 | }, 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/sambacha/isdx.git" 11 | }, 12 | "keywords": [ 13 | "solidity", 14 | "ethereum", 15 | "mev" 16 | ], 17 | "files": [ 18 | "/dist/**/*", 19 | "/contracts", 20 | "/contracts/base", 21 | "/contracts/interfaces", 22 | "/contracts/libraries", 23 | "/artifacts/contracts/**/*.json", 24 | "!artifacts/contracts/**/*.dbg.json", 25 | "!artifacts/contracts/test/**/*", 26 | "!artifacts/contracts/base/**/*", 27 | "/src/**/*" 28 | ], 29 | "author": "SEE CONTRIBUTORS", 30 | "license": "(MIT OR APACHE-2.0)", 31 | "dependencies": {}, 32 | "devDependencies": { 33 | "prettier": "2.6.0", 34 | "prettier-config-solidity": "1.7.0", 35 | "prettier-plugin-solidity": "1.0.0-beta.19" 36 | }, 37 | "bugs": { 38 | "url": "https://github.com/sambacha/isdx/issues" 39 | }, 40 | "homepage": "https://github.com/sambacha/isdx#readme" 41 | } 42 | -------------------------------------------------------------------------------- /scripts/common.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eo pipefail 4 | 5 | if [[ ${DEBUG} ]]; then 6 | set -x 7 | fi 8 | 9 | # All contracts are output to `out/addresses.json` by default 10 | OUT_DIR=${OUT_DIR:-$PWD/out} 11 | ADDRESSES_FILE=${ADDRESSES_FILE:-$OUT_DIR/"addresses.json"} 12 | # default to localhost rpc 13 | ETH_RPC_URL=${ETH_RPC_URL:-http://localhost:8545} 14 | 15 | # green log helper 16 | GREEN='\033[0;32m' 17 | NC='\033[0m' # No Color 18 | log() { 19 | printf '%b\n' "${GREEN}${*}${NC}" 20 | echo "" 21 | } 22 | 23 | # Coloured output helpers 24 | if command -v tput >/dev/null 2>&1; then 25 | if [ $(($(tput colors 2>/dev/null))) -ge 8 ]; then 26 | # Enable colors 27 | TPUT_RESET="$(tput sgr 0)" 28 | TPUT_YELLOW="$(tput setaf 3)" 29 | TPUT_RED="$(tput setaf 1)" 30 | TPUT_BLUE="$(tput setaf 4)" 31 | TPUT_GREEN="$(tput setaf 2)" 32 | TPUT_WHITE="$(tput setaf 7)" 33 | TPUT_BOLD="$(tput bold)" 34 | fi 35 | fi 36 | 37 | # ensure ETH_FROM is set and give a meaningful error message 38 | if [[ -z ${ETH_FROM} ]]; then 39 | echo "ETH_FROM not found, please set it and re-run the last command." 40 | exit 1 41 | fi 42 | 43 | # Make sure address is checksummed 44 | if [ "$ETH_FROM" != "$(seth --to-checksum-address "$ETH_FROM")" ]; then 45 | echo "ETH_FROM not checksummed, please format it with 'seth --to-checksum-address
'" 46 | exit 1 47 | fi 48 | 49 | # Setup addresses file 50 | cat >"$ADDRESSES_FILE" < deploy ContractName arg1 arg2 arg3` 57 | # (or omit the env vars if you have already set them) 58 | deploy() { 59 | NAME=$1 60 | ARGS=${@:2} 61 | 62 | # find file path 63 | CONTRACT_PATH=$(find ./src -name $NAME.sol) 64 | CONTRACT_PATH=${CONTRACT_PATH:2} 65 | 66 | # select the filename and the contract in it 67 | PATTERN=".contracts[\"$CONTRACT_PATH\"].$NAME" 68 | 69 | # get the constructor's signature 70 | ABI=$(jq -r "$PATTERN.abi" out/dapp.sol.json) 71 | SIG=$(echo "$ABI" | seth --abi-constructor) 72 | 73 | # get the bytecode from the compiled file 74 | BYTECODE=0x$(jq -r "$PATTERN.evm.bytecode.object" out/dapp.sol.json) 75 | 76 | # estimate gas 77 | GAS=$(seth estimate --create "$BYTECODE" "$SIG" $ARGS --rpc-url "$ETH_RPC_URL") 78 | 79 | # deploy 80 | ADDRESS=$(dapp create "$NAME" $ARGS -- --gas "$GAS" --rpc-url "$ETH_RPC_URL") 81 | 82 | # save the addrs to the json 83 | # TODO: It'd be nice if we could evolve this into a minimal versioning system 84 | # e.g. via commit / chainid etc. 85 | saveContract "$NAME" "$ADDRESS" 86 | 87 | echo "$ADDRESS" 88 | } 89 | 90 | # Call as `saveContract ContractName 0xYourAddress` to store the contract name 91 | # & address to the addresses json file 92 | saveContract() { 93 | # create an empty json if it does not exist 94 | if [[ ! -e $ADDRESSES_FILE ]]; then 95 | echo "{}" >"$ADDRESSES_FILE" 96 | fi 97 | result=$(cat "$ADDRESSES_FILE" | jq -r ". + {\"$1\": \"$2\"}") 98 | printf %s "$result" >"$ADDRESSES_FILE" 99 | } 100 | 101 | estimate_gas() { 102 | NAME=$1 103 | ARGS=${@:2} 104 | # select the filename and the contract in it 105 | PATTERN=".contracts[\"src/$NAME.sol\"].$NAME" 106 | 107 | # get the constructor's signature 108 | ABI=$(jq -r "$PATTERN.abi" out/dapp.sol.json) 109 | SIG=$(echo "$ABI" | seth --abi-constructor) 110 | 111 | # get the bytecode from the compiled file 112 | BYTECODE=0x$(jq -r "$PATTERN.evm.bytecode.object" out/dapp.sol.json) 113 | # estimate gas 114 | GAS=$(seth estimate --create "$BYTECODE" "$SIG" $ARGS --rpc-url "$ETH_RPC_URL") 115 | 116 | TXPRICE_RESPONSE=$(curl -sL https://api.txprice.com/v1) 117 | response=$(jq '.code' <<<"$TXPRICE_RESPONSE") 118 | if [[ $response != "200" ]]; then 119 | echo "Could not get gas information from ${TPUT_BOLD}txprice.com${TPUT_RESET}: https://api.txprice.com/v1" 120 | echo "response code: $response" 121 | else 122 | rapid=$(($(jq '.blockPrices[0].estimatedPrices[0].maxFeePerGas' <<<"$TXPRICE_RESPONSE"))) 123 | fast=$(($(jq '.blockPrices[0].estimatedPrices[1].maxFeePerGas' <<<"$TXPRICE_RESPONSE"))) 124 | standard=$(($(jq '.blockPrices[0].estimatedPrices[2].maxFeePerGas' <<<"$TXPRICE_RESPONSE"))) 125 | slow=$(($(jq '.blockPrices[0].estimatedPrices[3].maxFeePerGas' <<<"$TXPRICE_RESPONSE"))) 126 | basefee$(($(jq '.blockPrices[0].baseFeePerGas' <<<"$TXPRICE_RESPONSE"))) 127 | echo "Gas prices from ${TPUT_BOLD}txprice.com${TPUT_RESET}: https://api.txprice.com/v1" 128 | echo " \ 129 | ${TPUT_RED}Rapid: $rapid gwei ${TPUT_RESET} \n 130 | ${TPUT_YELLOW}Fast: $fast gwei \n 131 | ${TPUT_BLUE}Standard: $standard gwei \n 132 | ${TPUT_GREEN}Slow: $slow gwei${TPUT_RESET}" | column -t 133 | size=$(contract_size "$NAME") 134 | echo "Estimated Gas cost for deployment of $NAME: ${TPUT_BOLD}$GAS${TPUT_RESET} units of gas" 135 | echo "Contract Size: ${size} bytes" 136 | echo "Total cost for deployment:" 137 | rapid_cost=$(echo "scale=5; $GAS*$rapid" | bc) 138 | fast_cost=$(echo "scale=5; $GAS*$fast" | bc) 139 | standard_cost=$(echo "scale=5; $GAS*$standard" | bc) 140 | slow_cost=$(echo "scale=5; $GAS*$slow" | bc) 141 | echo " \ 142 | ${TPUT_RED}Rapid: $rapid_cost ETH ${TPUT_RESET} \n 143 | ${TPUT_YELLOW}Fast: $fast_cost ETH \n 144 | ${TPUT_BLUE}Standard: $standard_cost ETH \n 145 | ${TPUT_GREEN}Slow: $slow_cost ETH ${TPUT_RESET}" | column -t 146 | fi 147 | } 148 | 149 | contract_size() { 150 | NAME=$1 151 | ARGS=${@:2} 152 | # select the filename and the contract in it 153 | PATTERN=".contracts[\"src/$NAME.sol\"].$NAME" 154 | 155 | # get the bytecode from the compiled file 156 | BYTECODE=0x$(jq -r "$PATTERN.evm.bytecode.object" out/dapp.sol.json) 157 | length=$(echo "$BYTECODE" | wc -m) 158 | echo $(($length / 2)) 159 | } 160 | -------------------------------------------------------------------------------- /scripts/contract-size.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eo pipefail 4 | 5 | . $(dirname $0)/common.sh 6 | 7 | if [[ -z $contract ]]; then 8 | if [[ -z ${1} ]];then 9 | echo '"$contract" env variable is not set. Set it to the name of the contract you want to estimate size for.' 10 | exit 1 11 | else 12 | contract=${1} 13 | fi 14 | fi 15 | contract_size=$(contract_size ${contract}) 16 | echo "Contract Name: ${contract}" 17 | echo "Contract Size: ${contract_size} bytes" 18 | echo "$(( 24576 - ${contract_size} )) bytes left to reach the smart contract size limit of 24576 bytes." 19 | -------------------------------------------------------------------------------- /scripts/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eo pipefail 4 | 5 | # import the deployment helpers 6 | . $(dirname $0)/common.sh 7 | 8 | # import config with arguments based on contract and network 9 | . $(dirname $0)/helper-config.sh 10 | 11 | # Deploy 12 | # Contract will be counter unless overriden on the command line 13 | : ${CONTRACT:=Greeter} 14 | echo "Deploying $CONTRACT to $NETWORK with arguments: $arguments" 15 | Addr=$(deploy $CONTRACT $arguments) 16 | log "$CONTRACT deployed at:" $Addr 17 | -------------------------------------------------------------------------------- /scripts/estimate-gas.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eo pipefail 4 | 5 | . $(dirname $0)/common.sh 6 | 7 | if [[ -z $contract ]]; then 8 | if [[ -z ${1} ]];then 9 | echo '"$contract" env variable is not set. Set it to the name of the contract you want to estimate gas cost for.' 10 | exit 1 11 | else 12 | contract=${1} 13 | fi 14 | fi 15 | 16 | estimate_gas $contract 17 | 18 | 19 | -------------------------------------------------------------------------------- /scripts/helper-config.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Defaults 4 | # Add your defaults here 5 | # For example: 6 | # address=0x01be23585060835e02b77ef475b0cc51aa1e0709 7 | 8 | # Add your contract arguments default here 9 | arguments="" 10 | 11 | if [ "$NETWORK" = "rinkeby" ] 12 | then 13 | : # Add arguments only for rinkeby here! 14 | # like: 15 | # address=0x01be23585060835e02b77ef475b0cc51aa1e0709 16 | elif [ "$NETWORK" = "mainnet" ] 17 | then 18 | : # Add arguments only for mainnet here! 19 | # like: 20 | # address=0x01be23585060835e02b77ef475b0cc51aa1e0709 21 | fi 22 | 23 | if [ "$CONTRACT" = "Greeter" ] 24 | then 25 | : # Add conditional arguments here for contracts 26 | # arguments=$interval 27 | fi 28 | -------------------------------------------------------------------------------- /scripts/run-temp-testnet.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eo pipefail 4 | 5 | # Utility for running a temporary dapp testnet w/ an ephemeral account 6 | # to be used for deployment tests 7 | 8 | # make a temp dir to store testnet info 9 | export TMPDIR=$(mktemp -d) 10 | 11 | # clean up 12 | trap 'killall geth && sleep 3 && rm -rf "$TMPDIR"' EXIT 13 | trap "exit 1" SIGINT SIGTERM 14 | 15 | # test helper 16 | error() { 17 | printf 1>&2 "fail: function '%s' at line %d.\n" "${FUNCNAME[1]}" "${BASH_LINENO[0]}" 18 | printf 1>&2 "got: %s" "$output" 19 | exit 1 20 | } 21 | 22 | # launch the testnet 23 | dapp testnet --dir "$TMPDIR" & 24 | # wait for it to launch (can't go <3s) 25 | sleep 3 26 | 27 | # set the RPC URL to the local testnet 28 | export ETH_RPC_URL=http://127.0.0.1:8545 29 | 30 | # get the created account (it's unlocked so we only need to set the address) 31 | export ETH_FROM=$(seth ls --keystore $TMPDIR/8545/keystore | cut -f1) 32 | -------------------------------------------------------------------------------- /scripts/test-deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eo pipefail 4 | 5 | # bring up the network 6 | . $(dirname $0)/run-temp-testnet.sh 7 | 8 | # run the deploy script 9 | . $(dirname $0)/deploy.sh 10 | 11 | # get the address 12 | addr=$(jq -r '.Greeter' out/addresses.json) 13 | 14 | # the initial greeting must be empty 15 | greeting=$(seth call $addr 'greeting()(string)') 16 | [[ $greeting = "" ]] || error 17 | 18 | # set it to a value 19 | seth send $addr \ 20 | 'greet(string memory)' '"yo"' \ 21 | --keystore $TMPDIR/8545/keystore \ 22 | --password /dev/null 23 | 24 | sleep 1 25 | 26 | # should be set afterwards 27 | greeting=$(seth call $addr 'greeting()(string)') 28 | [[ $greeting = "yo" ]] || error 29 | 30 | echo "Success." 31 | -------------------------------------------------------------------------------- /src/ACL/Trust.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0-only 2 | pragma solidity >=0.7.0; 3 | 4 | /// @notice Ultra minimal authorization logic for smart contracts. 5 | /// @author From https://github.com/Rari-Capital/solmate/blob/fab107565a51674f3a3b5bfdaacc67f6179b1a9b/src/auth/Trust.sol 6 | abstract contract Trust { 7 | event UserTrustUpdated(address indexed user, bool trusted); 8 | 9 | mapping(address => bool) public isTrusted; 10 | 11 | constructor(address initialUser) { 12 | isTrusted[initialUser] = true; 13 | 14 | emit UserTrustUpdated(initialUser, true); 15 | } 16 | 17 | function setIsTrusted(address user, bool trusted) public virtual requiresTrust { 18 | isTrusted[user] = trusted; 19 | 20 | emit UserTrustUpdated(user, trusted); 21 | } 22 | 23 | modifier requiresTrust() { 24 | require(isTrusted[msg.sender], "UNTRUSTED"); 25 | 26 | _; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/AbiDecodeTest.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.22 <0.7.0; 2 | 3 | contract AbiDecodeTest { 4 | //test data: 0xb82fedbbee8ea5499c660b8322896ada651fc8774b4a23e582b75e8f8e51d629da556a7400000000000000000000000035d76d9fad7c95873266deffd2be50ce2c350c37dbb31252d9bddb4e4d362c7b9c80cba74732280737af97971f42ccbdc716f3f3efb1db366880e52d09b1bfd59842e833f3004088892b7d14b9ce9e957cea9a82 5 | 6 | //execution cost: 860 gas 7 | function abiDecodeTest( 8 | bytes memory _data 9 | ) 10 | public 11 | pure 12 | returns( 13 | bytes4 sig, 14 | bytes32 label, 15 | address account, 16 | bytes32 pubkeyA, 17 | bytes32 pubkeyB 18 | ) 19 | { 20 | assembly { 21 | sig := mload(add(_data, 32)) 22 | label := mload(add(_data, 36)) 23 | account := mload(add(_data, 68)) 24 | pubkeyA := mload(add(_data, 100)) 25 | pubkeyB := mload(add(_data, 132)) 26 | } 27 | } 28 | 29 | //execution cost: 1294 gas 30 | function abiDecodeTest2( 31 | bytes calldata _data 32 | ) 33 | external 34 | pure 35 | returns( 36 | bytes4 sig, 37 | bytes32 label, 38 | address account, 39 | bytes32 pubkeyA, 40 | bytes32 pubkeyB 41 | ) 42 | { 43 | sig = _data[0] | bytes4(_data[1]) >> 8 | bytes4(_data[2]) >> 16 | bytes4(_data[3]) >> 24; 44 | (label, account, pubkeyA, pubkeyB) = abi.decode(_data[4:], (bytes32, address, bytes32, bytes32)); 45 | } 46 | 47 | //execution cost: 1192 gas 48 | function abiDecodeTest3( 49 | bytes calldata _data 50 | ) 51 | external 52 | pure 53 | returns( 54 | bytes4 sig, 55 | bytes32 label, 56 | address account, 57 | bytes32 pubkeyA, 58 | bytes32 pubkeyB 59 | ) 60 | { 61 | sig = getSelector(_data); 62 | (label, account, pubkeyA, pubkeyB) = abi.decode(_data[4:], (bytes32, address, bytes32, bytes32)); 63 | } 64 | 65 | function getSelector(bytes memory _data) private pure returns(bytes4 sig) { 66 | assembly { 67 | sig := mload(add(_data, 32)) 68 | } 69 | } 70 | 71 | //execution cost: 1885 gas 72 | function abiDecodeTest4( 73 | bytes calldata _data 74 | ) 75 | external 76 | pure 77 | returns( 78 | bytes4 sig, 79 | bytes32 label, 80 | address account, 81 | bytes32 pubkeyA, 82 | bytes32 pubkeyB 83 | ) 84 | { 85 | sig = getSelector(_data); 86 | (label, account, pubkeyA, pubkeyB) = abi.decode(slice(_data,4,_data.length-4), (bytes32, address, bytes32, bytes32)); 87 | } 88 | 89 | function getSelector(bytes memory _data) private pure returns(bytes4 sig) { 90 | assembly { 91 | sig := mload(add(_data, 32)) 92 | } 93 | } 94 | 95 | function slice(bytes memory _bytes, uint _start, uint _length) private pure returns (bytes memory) { 96 | require(_bytes.length >= (_start + _length)); 97 | 98 | bytes memory tempBytes; 99 | 100 | assembly { 101 | switch iszero(_length) 102 | case 0 { 103 | // Get a location of some free memory and store it in tempBytes as 104 | // Solidity does for memory variables. 105 | tempBytes := mload(0x40) 106 | 107 | // The first word of the slice result is potentially a partial 108 | // word read from the original array. To read it, we calculate 109 | // the length of that partial word and start copying that many 110 | // bytes into the array. The first word we copy will start with 111 | // data we don't care about, but the last `lengthmod` bytes will 112 | // land at the beginning of the contents of the new array. When 113 | // we're done copying, we overwrite the full first word with 114 | // the actual length of the slice. 115 | let lengthmod := and(_length, 31) 116 | 117 | // The multiplication in the next line is necessary 118 | // because when slicing multiples of 32 bytes (lengthmod == 0) 119 | // the following copy loop was copying the origin's length 120 | // and then ending prematurely not copying everything it should. 121 | let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) 122 | let end := add(mc, _length) 123 | 124 | for { 125 | // The multiplication in the next line has the same exact purpose 126 | // as the one above. 127 | let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) 128 | } lt(mc, end) { 129 | mc := add(mc, 0x20) 130 | cc := add(cc, 0x20) 131 | } { 132 | mstore(mc, mload(cc)) 133 | } 134 | 135 | mstore(tempBytes, _length) 136 | 137 | //update free-memory pointer 138 | //allocating the array padded to 32 bytes like the compiler does now 139 | mstore(0x40, and(add(mc, 31), not(31))) 140 | } 141 | //if we want a zero-length slice let's just return a zero-length array 142 | default { 143 | tempBytes := mload(0x40) 144 | 145 | mstore(0x40, add(tempBytes, 0x20)) 146 | } 147 | } 148 | 149 | return tempBytes; 150 | } 151 | 152 | 153 | } 154 | -------------------------------------------------------------------------------- /src/AccountWatcher.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.4; 3 | 4 | struct Account { 5 | uint256 etherBalance; 6 | TokenBalance[] tokenBalances; 7 | } 8 | 9 | struct TokenBalance { 10 | bool callSuccess; 11 | uint256 balance; 12 | } 13 | 14 | interface ERC20Interface { 15 | function balanceOf(address account) external view returns (uint256 balance); 16 | } 17 | 18 | interface AccountWatcherInterface { 19 | function balancesOf(ERC20Interface[] calldata tokens, address[] calldata accounts) 20 | external 21 | view 22 | returns (Account[] memory accountBalances); 23 | } 24 | 25 | /// Quickly check the Ether balance, as well as the balance of each 26 | /// supplied ERC20 token, for a collection of accounts. 27 | /// @author 0age 28 | contract AccountWatcher is AccountWatcherInterface { 29 | function balancesOf(ERC20Interface[] calldata tokens, address[] calldata accounts) 30 | external 31 | view 32 | override 33 | returns (Account[] memory) 34 | { 35 | Account[] memory accountBalances = new Account[](accounts.length); 36 | 37 | for (uint256 i = 0; i < accounts.length; i++) { 38 | address account = accounts[i]; 39 | 40 | TokenBalance[] memory tokenBalances = new TokenBalance[](tokens.length); 41 | 42 | for (uint256 j = 0; j < tokens.length; j++) { 43 | ERC20Interface token = tokens[j]; 44 | (bool success, bytes memory returnData) = address(token).staticcall( 45 | abi.encodeWithSelector(token.balanceOf.selector, account) 46 | ); 47 | 48 | if (success && returnData.length >= 32) { 49 | TokenBalance memory tokenBalance; 50 | 51 | tokenBalance.callSuccess = true; 52 | tokenBalance.balance = abi.decode(returnData, (uint256)); 53 | 54 | tokenBalances[j] = tokenBalance; 55 | } 56 | } 57 | 58 | accountBalances[i].etherBalance = account.balance; 59 | accountBalances[i].tokenBalances = tokenBalances; 60 | } 61 | 62 | return accountBalances; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/AllowancesHelper.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.4; 4 | 5 | interface IERC20 { 6 | function allowance(address spender, address owner) external view returns (uint256); 7 | } 8 | 9 | contract AllowancesHelper { 10 | struct Allowance { 11 | address owner; 12 | address spender; 13 | uint256 amount; 14 | address token; 15 | } 16 | 17 | function allowances( 18 | address ownerAddress, 19 | address[] memory tokensAddresses, 20 | address[] memory spenderAddresses 21 | ) external view returns (Allowance[] memory) { 22 | uint256 spenderIdx; 23 | uint256 tokenIdx; 24 | uint256 numberOfAllowances; 25 | 26 | // Calculate number of allowances 27 | for (tokenIdx = 0; tokenIdx < tokensAddresses.length; tokenIdx++) { 28 | for (spenderIdx = 0; spenderIdx < spenderAddresses.length; spenderIdx++) { 29 | address tokenAddress = tokensAddresses[tokenIdx]; 30 | address spenderAddress = spenderAddresses[spenderIdx]; 31 | IERC20 token = IERC20(tokenAddress); 32 | uint256 amount = token.allowance(ownerAddress, spenderAddress); 33 | if (amount > 0) { 34 | numberOfAllowances++; 35 | } 36 | } 37 | } 38 | 39 | // Fetch allowances 40 | Allowance[] memory _allowances = new Allowance[](numberOfAllowances); 41 | uint256 allowanceIdx; 42 | for (tokenIdx = 0; tokenIdx < tokensAddresses.length; tokenIdx++) { 43 | for (spenderIdx = 0; spenderIdx < spenderAddresses.length; spenderIdx++) { 44 | address spenderAddress = spenderAddresses[spenderIdx]; 45 | address tokenAddress = tokensAddresses[tokenIdx]; 46 | IERC20 token = IERC20(tokenAddress); 47 | uint256 amount = token.allowance(ownerAddress, spenderAddress); 48 | if (amount > 0) { 49 | Allowance memory allowance = Allowance({ 50 | owner: ownerAddress, 51 | spender: spenderAddress, 52 | amount: amount, 53 | token: tokenAddress 54 | }); 55 | _allowances[allowanceIdx] = allowance; 56 | allowanceIdx++; 57 | } 58 | } 59 | } 60 | return _allowances; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Approvals.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.10; 4 | 5 | interface IERC20 { 6 | function allowance(address spender, address owner) external view returns (uint256); 7 | } 8 | 9 | contract AllowancesHelper { 10 | struct Allowance { 11 | address owner; 12 | address spender; 13 | uint256 amount; 14 | address token; 15 | } 16 | 17 | function allowances( 18 | address ownerAddress, 19 | address[] memory tokensAddresses, 20 | address[] memory spenderAddresses 21 | ) external view returns (Allowance[] memory) { 22 | uint256 spenderIdx; 23 | uint256 tokenIdx; 24 | uint256 numberOfAllowances; 25 | 26 | // Calculate number of allowances 27 | for (tokenIdx = 0; tokenIdx < tokensAddresses.length; tokenIdx++) { 28 | for (spenderIdx = 0; spenderIdx < spenderAddresses.length; spenderIdx++) { 29 | address tokenAddress = tokensAddresses[tokenIdx]; 30 | address spenderAddress = spenderAddresses[spenderIdx]; 31 | IERC20 token = IERC20(tokenAddress); 32 | uint256 amount = token.allowance(ownerAddress, spenderAddress); 33 | if (amount > 0) { 34 | numberOfAllowances++; 35 | } 36 | } 37 | } 38 | 39 | // Fetch allowances 40 | Allowance[] memory _allowances = new Allowance[](numberOfAllowances); 41 | uint256 allowanceIdx; 42 | for (tokenIdx = 0; tokenIdx < tokensAddresses.length; tokenIdx++) { 43 | for (spenderIdx = 0; spenderIdx < spenderAddresses.length; spenderIdx++) { 44 | address spenderAddress = spenderAddresses[spenderIdx]; 45 | address tokenAddress = tokensAddresses[tokenIdx]; 46 | IERC20 token = IERC20(tokenAddress); 47 | uint256 amount = token.allowance(ownerAddress, spenderAddress); 48 | if (amount > 0) { 49 | Allowance memory allowance = Allowance({ 50 | owner: ownerAddress, 51 | spender: spenderAddress, 52 | amount: amount, 53 | token: tokenAddress 54 | }); 55 | _allowances[allowanceIdx] = allowance; 56 | allowanceIdx++; 57 | } 58 | } 59 | } 60 | return _allowances; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/BalanceScanner.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.4; 4 | 5 | /** 6 | * @title An Ether or token balance scanner 7 | * @author Maarten Zuidhoorn 8 | * @author Luit Hollander 9 | */ 10 | contract BalanceScanner { 11 | struct Result { 12 | bool success; 13 | bytes data; 14 | } 15 | 16 | /** 17 | * @notice Get the Ether balance for all addresses specified 18 | * @param addresses The addresses to get the Ether balance for 19 | * @return results The Ether balance for all addresses in the same order as specified 20 | */ 21 | function etherBalances(address[] calldata addresses) 22 | external 23 | view 24 | returns (Result[] memory results) 25 | { 26 | results = new Result[](addresses.length); 27 | 28 | for (uint256 i = 0; i < addresses.length; i++) { 29 | results[i] = Result(true, abi.encode(addresses[i].balance)); 30 | } 31 | } 32 | 33 | /** 34 | * @notice Get the ERC-20 token balance of `token` for all addresses specified 35 | * @dev This does not check if the `token` address specified is actually an ERC-20 token 36 | * @param addresses The addresses to get the token balance for 37 | * @param token The address of the ERC-20 token contract 38 | * @return results The token balance for all addresses in the same order as specified 39 | */ 40 | function tokenBalances(address[] calldata addresses, address token) 41 | external 42 | view 43 | returns (Result[] memory results) 44 | { 45 | results = new Result[](addresses.length); 46 | 47 | for (uint256 i = 0; i < addresses.length; i++) { 48 | bytes memory data = abi.encodeWithSignature("balanceOf(address)", addresses[i]); 49 | results[i] = staticCall(token, data, 20000); 50 | } 51 | } 52 | 53 | /** 54 | * @notice Get the ERC-20 token balance from multiple contracts for a single owner 55 | * @param owner The address of the token owner 56 | * @param contracts The addresses of the ERC-20 token contracts 57 | * @return results The token balances in the same order as the addresses specified 58 | */ 59 | function tokensBalance(address owner, address[] calldata contracts) 60 | external 61 | view 62 | returns (Result[] memory results) 63 | { 64 | results = new Result[](contracts.length); 65 | 66 | bytes memory data = abi.encodeWithSignature("balanceOf(address)", owner); 67 | for (uint256 i = 0; i < contracts.length; i++) { 68 | results[i] = staticCall(contracts[i], data, 20000); 69 | } 70 | } 71 | 72 | /** 73 | * @notice Call multiple contracts with the provided arbitrary data 74 | * @param contracts The contracts to call 75 | * @param data The data to call the contracts with 76 | * @return results The raw result of the contract calls 77 | */ 78 | function call(address[] calldata contracts, bytes[] calldata data) 79 | external 80 | view 81 | returns (Result[] memory results) 82 | { 83 | return call(contracts, data, gasleft()); 84 | } 85 | 86 | /** 87 | * @notice Call multiple contracts with the provided arbitrary data 88 | * @param contracts The contracts to call 89 | * @param data The data to call the contracts with 90 | * @param gas The amount of gas to call the contracts with 91 | * @return results The raw result of the contract calls 92 | */ 93 | function call( 94 | address[] calldata contracts, 95 | bytes[] calldata data, 96 | uint256 gas 97 | ) public view returns (Result[] memory results) { 98 | require(contracts.length == data.length, "Length must be equal"); 99 | results = new Result[](contracts.length); 100 | 101 | for (uint256 i = 0; i < contracts.length; i++) { 102 | results[i] = staticCall(contracts[i], data[i], gas); 103 | } 104 | } 105 | 106 | /** 107 | * @notice Static call a contract with the provided data 108 | * @param target The address of the contract to call 109 | * @param data The data to call the contract with 110 | * @param gas The amount of gas to forward to the call 111 | * @return result The result of the contract call 112 | */ 113 | function staticCall( 114 | address target, 115 | bytes memory data, 116 | uint256 gas 117 | ) private view returns (Result memory) { 118 | uint256 size = codeSize(target); 119 | 120 | if (size > 0) { 121 | (bool success, bytes memory result) = target.staticcall{ gas: gas }(data); 122 | if (success) { 123 | return Result(success, result); 124 | } 125 | } 126 | 127 | return Result(false, ""); 128 | } 129 | 130 | /** 131 | * @notice Get code size of address 132 | * @param _address The address to get code size from 133 | * @return size Unsigned 256-bits integer 134 | */ 135 | function codeSize(address _address) private view returns (uint256 size) { 136 | // solhint-disable-next-line no-inline-assembly 137 | assembly { 138 | size := extcodesize(_address) 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/BalancesAndAllowancesHelper.sol: -------------------------------------------------------------------------------- 1 | /// SPDX-License-Identifier: MIT 2 | pragma solidity ^0.7.6; 3 | 4 | /// @author 0x66666600e43c6d9e1a249d29d58639dedfcd9ade 5 | 6 | interface IERC20 { 7 | function balanceOf(address addr) external view returns (uint256); 8 | 9 | function allowance(address owner, address spender) external view returns (uint256); 10 | } 11 | 12 | /// @title BalancesAndAllowancesHelper 13 | contract BalancesAndAllowancesHelper { 14 | uint256 private constant infinityAllowance = 1 << 248; 15 | 16 | function getBalances(IERC20[] calldata tokens, address wallet) 17 | external 18 | view 19 | returns (uint256[] memory indexAndBalance) 20 | { 21 | uint256 counter = 0; 22 | uint256[] memory tmp = new uint256[](tokens.length); 23 | for (uint256 i = 0; i < tokens.length; i++) { 24 | try tokens[i].balanceOf(wallet) returns (uint256 balance) { 25 | if (balance == 0) { 26 | continue; 27 | } 28 | 29 | tmp[counter] = (i << 248) | balance; 30 | counter++; 31 | } catch {} 32 | } 33 | 34 | indexAndBalance = new uint256[](counter); 35 | for (uint256 i = 0; i < counter; i++) { 36 | indexAndBalance[i] = tmp[i]; 37 | } 38 | } 39 | 40 | function getAllowances( 41 | IERC20[] calldata tokens, 42 | address owner, 43 | address spender 44 | ) external view returns (uint256[] memory indexAndAllowance) { 45 | uint256 counter = 0; 46 | uint256[] memory tmp = new uint256[](tokens.length); 47 | for (uint256 i = 0; i < tokens.length; i++) { 48 | try tokens[i].allowance(owner, spender) returns (uint256 allowance) { 49 | if (allowance == 0) { 50 | continue; 51 | } 52 | 53 | if (allowance > infinityAllowance) { 54 | tmp[counter] = (i << 248) | (1 << 247); 55 | } else { 56 | tmp[counter] = (i << 248) | allowance; 57 | } 58 | counter++; 59 | } catch {} 60 | } 61 | 62 | indexAndAllowance = new uint256[](counter); 63 | for (uint256 i = 0; i < counter; i++) { 64 | indexAndAllowance[i] = tmp[i]; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/BytesParsing.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | pragma solidity >=0.8.5 <0.9.0; 4 | 5 | contract BytesParsing { 6 | // example bytes calldata: 0x3A1174741911F257FFCA965A00000002010000 7 | // color codes: #3a1174, #741911, #f257ff, #ca965a, #000000 8 | // numbers: 2, 1, 0, 0 9 | 10 | function uint8tohexchar(uint8 i) internal pure returns (uint8) { 11 | return (i > 9) ? 12 | (i + 87) : // ascii a-f 13 | (i + 48); // ascii 0-9 14 | } 15 | 16 | function bytes3tohexstr(bytes3 c) internal pure returns (string memory) { 17 | uint24 i = uint24(c); 18 | bytes memory o = new bytes(6); 19 | uint24 mask = 0x00000f; 20 | o[5] = bytes1(uint8tohexchar(uint8(i & mask))); 21 | i = i >> 4; 22 | o[4] = bytes1(uint8tohexchar(uint8(i & mask))); 23 | i = i >> 4; 24 | o[3] = bytes1(uint8tohexchar(uint8(i & mask))); 25 | i = i >> 4; 26 | o[2] = bytes1(uint8tohexchar(uint8(i & mask))); 27 | i = i >> 4; 28 | o[1] = bytes1(uint8tohexchar(uint8(i & mask))); 29 | i = i >> 4; 30 | o[0] = bytes1(uint8tohexchar(uint8(i & mask))); 31 | return string(o); 32 | } 33 | 34 | function sliceBytes1(bytes calldata features) public pure returns(string memory) { 35 | bytes3 c = bytes3(features[0:3]); 36 | return bytes3tohexstr(c); 37 | } 38 | 39 | function sliceBytes2(bytes calldata features) public pure returns(string memory) { 40 | bytes3 c = bytes3(features[3:6]); 41 | return bytes3tohexstr(c); 42 | } 43 | 44 | function sliceBytes3(bytes calldata features) public pure returns(string memory) { 45 | bytes3 c = bytes3(features[6:9]); 46 | return bytes3tohexstr(c); 47 | } 48 | 49 | function sliceBytes4(bytes calldata features) public pure returns(string memory) { 50 | bytes3 c = bytes3(features[9:12]); 51 | return bytes3tohexstr(c); 52 | } 53 | 54 | function sliceBytes5(bytes calldata features) public pure returns(string memory) { 55 | bytes3 c = bytes3(features[12:15]); 56 | return bytes3tohexstr(c); 57 | } 58 | 59 | function sliceBytes6(bytes calldata features) public pure returns(uint8) { 60 | bytes1 a = bytes1(features[15:16]); 61 | return uint8(a); 62 | } 63 | 64 | function sliceBytes7(bytes calldata features) public pure returns(uint8) { 65 | bytes1 a = bytes1(features[16:17]); 66 | return uint8(a); 67 | } 68 | 69 | function sliceBytes8(bytes calldata features) public pure returns(uint8) { 70 | bytes1 a = bytes1(features[17:18]); 71 | return uint8(a); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/CallFunctionWithoutContract.sol: -------------------------------------------------------------------------------- 1 | /// SPDX-License-Identifier: MIT OR APACHE-2.0 2 | pragma solidity ^0.8.7; 3 | 4 | // source: twitter.com/PatrickAlphaC/status/1517156283215802368 5 | 6 | /// @title CallFunctionWithoutContract 7 | contract CallFunctionWithoutContract { 8 | address public s_selectorsAndSignaturesAddress; 9 | 10 | constructor(address selectorsAndSignaturesAddress) { 11 | s_selectorsAndSignaturesAddress = selectorsAndSignaturesAddress; 12 | } 13 | 14 | // you could use this to change state 15 | function callFunctionDirectly(bytes calldata calldata) public returns (bytes4, bool) { 16 | (bool success, bytes memory returnData) = s_selectorsAndSignaturesAddress.call( 17 | abi.encodeWithSignature("getSelectorThree(bytes)", callData) 18 | ); 19 | return (bytes4(returnData), success); 20 | } 21 | 22 | // with a staticcall, we can have this be a view function! 23 | function staticCallFunctionDirectly() public view returns (bytes4, bool) { 24 | (bool success, bytes memory returnData) = s_selectorsAndSignaturesAddress.staticcalll( 25 | abi.encodeWithSignature("getSelectorone()") 26 | ); 27 | return (bytes4(returnData), success); 28 | } 29 | 30 | function callTransferFunctionDirectly(address someAddress, uint256 amount) 31 | public 32 | returns (bytes4, booll) 33 | { 34 | (bool success, bytes memory returnData) = s_selectorsAndSignaturesAddress.call( 35 | abi.encodeWithSignature("transfer(address, uint256)", someAddress, amount) 36 | ); 37 | return (bytes4(returnData), success); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/CalldataUtils.lib.sol: -------------------------------------------------------------------------------- 1 | /// SPDX-License-Identifier: GPL-3.0 2 | pragma solidity ^0.8.7 <0.9.0; 3 | 4 | // Gas efficient calldata parser 5 | // https://github.com/ethereum/solidity/issues/9439#issuecomment-660134770 6 | 7 | library CalldataUtils { 8 | function getSig(bytes memory _data) internal pure returns (bytes4 sig) { 9 | assembly { 10 | sig := mload(add(_data, 32)) 11 | } 12 | } 13 | 14 | function slice( 15 | bytes memory _bytes, 16 | uint256 _start, 17 | uint256 _length 18 | ) internal pure returns (bytes memory) { 19 | require(_bytes.length >= (_start + _length)); 20 | 21 | bytes memory tempBytes; 22 | 23 | assembly { 24 | switch iszero(_length) 25 | case 0 { 26 | // Get a location of some free memory and store it in tempBytes as 27 | // Solidity does for memory variables. 28 | tempBytes := mload(0x40) 29 | 30 | // The first word of the slice result is potentially a partial 31 | // word read from the original array. To read it, we calculate 32 | // the length of that partial word and start copying that many 33 | // bytes into the array. The first word we copy will start with 34 | // data we don't care about, but the last `lengthmod` bytes will 35 | // land at the beginning of the contents of the new array. When 36 | // we're done copying, we overwrite the full first word with 37 | // the actual length of the slice. 38 | let lengthmod := and(_length, 31) 39 | 40 | // The multiplication in the next line is necessary 41 | // because when slicing multiples of 32 bytes (lengthmod == 0) 42 | // the following copy loop was copying the origin's length 43 | // and then ending prematurely not copying everything it should. 44 | let mc := add( 45 | add(tempBytes, lengthmod), 46 | mul(0x20, iszero(lengthmod)) 47 | ) 48 | let end := add(mc, _length) 49 | 50 | for { 51 | // The multiplication in the next line has the same exact purpose 52 | // as the one above. 53 | let cc := add( 54 | add( 55 | add(_bytes, lengthmod), 56 | mul(0x20, iszero(lengthmod)) 57 | ), 58 | _start 59 | ) 60 | } lt(mc, end) { 61 | mc := add(mc, 0x20) 62 | cc := add(cc, 0x20) 63 | } { 64 | mstore(mc, mload(cc)) 65 | } 66 | 67 | mstore(tempBytes, _length) 68 | 69 | //update free-memory pointer 70 | //allocating the array padded to 32 bytes like the compiler does now 71 | mstore(0x40, and(add(mc, 31), not(31))) 72 | } 73 | //if we want a zero-length slice let's just return a zero-length array 74 | default { 75 | tempBytes := mload(0x40) 76 | 77 | mstore(0x40, add(tempBytes, 0x20)) 78 | } 79 | } 80 | 81 | return tempBytes; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/CodeHashCache.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.4; 3 | 4 | /** 5 | * @title CodeHashCache 6 | * @author 0age 7 | * @notice This contract allows callers to register the runtime code hash of any 8 | * contract that is currently deployed with runtime code. It then allows callers 9 | * to determine whether or not the runtime code hash of any registered contract 10 | * has been altered since it was initially registered. A critical consideration 11 | * to bear in mind is that registered contracts can still be destroyed and later 12 | * redeployed with the same runtime code - their runtime code hash will be the 13 | * same, but their creation code may differ, and their contract storage will be 14 | * completely wiped upon destruction. 15 | */ 16 | contract CodeHashCache { 17 | // Maintain a mapping of runtime code hashes of deployed contracts. 18 | mapping(address => bytes32) private _cachedHashes; 19 | 20 | /** 21 | * @notice Register a target contract's current runtime code hash. This call 22 | * will revert if the supplied target contract has already been registered or 23 | * does not currently have any runtime code. 24 | * @param target address The contract to retrieve and store the runtime code 25 | * hash for. 26 | */ 27 | function registerCodeHash(address target) external { 28 | // Ensure that the target contract has not already had a hash registered. 29 | require(_cachedHashes[target] == bytes32(0), "Target already registered."); 30 | 31 | // Ensure that the target contract currently has runtime code. 32 | uint256 currentCodeSize; 33 | assembly { 34 | currentCodeSize := extcodesize(target) 35 | } 36 | require(currentCodeSize > 0, "Target currently has no runtime code."); 37 | 38 | // Retrieve the current runtime code hash of the target contract. 39 | bytes32 currentCodeHash; 40 | assembly { 41 | currentCodeHash := extcodehash(target) 42 | } 43 | 44 | // Register the runtime code hash for the target contract. 45 | _cachedHashes[target] = currentCodeHash; 46 | } 47 | 48 | /** 49 | * @notice View function to determine if the current runtime code hash of a 50 | * target contract matches the registered runtime code hash for the target 51 | * contract. Reverts if no runtime code hash has been registered yet for the 52 | * target contract. 53 | * @param target address The contract to retrieve the runtime code hash for, 54 | * which will be compared against the runtime code hash that was initially 55 | * registered for that contract. 56 | * @return codeHashMatchesRegisteredCodeHash - a boolean signifying that the target contract's runtime code has 57 | * not been altered since it was initially registered. 58 | */ 59 | function matchesRegisteredCodeHash(address target) 60 | external 61 | view 62 | returns (bool codeHashMatchesRegisteredCodeHash) 63 | { 64 | // Get the runtime code hash that is currently registered for the target. 65 | bytes32 cachedCodeHash = _cachedHashes[target]; 66 | 67 | // Ensure that the target contract has already had a code hash registered. 68 | require(cachedCodeHash != bytes32(0), "Target not yet registered."); 69 | 70 | // Retrieve the current runtime code hash of the target contract. 71 | bytes32 currentCodeHash; 72 | assembly { 73 | currentCodeHash := extcodehash(target) 74 | } 75 | 76 | // Compare current runtime code hash to registered runtime code hash. 77 | codeHashMatchesRegisteredCodeHash = currentCodeHash == cachedCodeHash; 78 | } 79 | 80 | /** 81 | * @notice View function to retrieve the runtime code hash registered for the 82 | * target contract. Returns bytes32(0) if there is no runtime code hash 83 | * registered for the target. 84 | * @param target address The contract to retrieve the registered runtime code 85 | * hash for. 86 | * @return registeredCodeHash - the runtime code hash registered for the target contract. Returns 87 | * bytes32(0) if there runtime code hash has been registered for the target. 88 | */ 89 | function getRegisteredCodeHash(address target) 90 | external 91 | view 92 | returns (bytes32 registeredCodeHash) 93 | { 94 | // Get the runtime code hash that is currently registered for the target. 95 | registeredCodeHash = _cachedHashes[target]; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/CounterfactualFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | /****************************************************************************** 4 | * Copyright 2020 IEXEC BLOCKCHAIN TECH * 5 | * * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); * 7 | * you may not use this file except in compliance with the License. * 8 | * You may obtain a copy of the License at * 9 | * * 10 | * http://www.apache.org/licenses/LICENSE-2.0 * 11 | * * 12 | * Unless required by applicable law or agreed to in writing, software * 13 | * distributed under the License is distributed on an "AS IS" BASIS, * 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 15 | * See the License for the specific language governing permissions and * 16 | * limitations under the License. * 17 | ******************************************************************************/ 18 | 19 | pragma solidity ^0.6.0; 20 | 21 | contract CounterfactualFactory { 22 | function _create2(bytes memory _code, bytes32 _salt) internal returns (address) { 23 | bytes memory code = _code; 24 | bytes32 salt = _salt; 25 | address addr; 26 | // solium-disable-next-line security/no-inline-assembly 27 | assembly { 28 | addr := create2(0, add(code, 0x20), mload(code), salt) 29 | if iszero(extcodesize(addr)) { 30 | revert(0, 0) 31 | } 32 | } 33 | return addr; 34 | } 35 | 36 | function _predictAddress(bytes memory _code, bytes32 _salt) internal view returns (address) { 37 | return 38 | address( 39 | bytes20( 40 | keccak256( 41 | abi.encodePacked(bytes1(0xff), address(this), _salt, keccak256(_code)) 42 | ) << 0x60 43 | ) 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/ERC20InvalidMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.4; 4 | 5 | import "./ERC20Mock.sol"; 6 | 7 | contract ERC20InvalidMock is ERC20Mock { 8 | address public sender; 9 | 10 | constructor(address initialAccount, uint256 initialBalance) 11 | payable 12 | ERC20Mock(initialAccount, initialBalance) 13 | { 14 | // noop 15 | } 16 | 17 | /** 18 | * @dev This function is not ERC-20 compliant and will cause STATICCALLs to fail. It exists for testing purposes only. 19 | */ 20 | function balanceOf(address account) public override returns (uint256) { 21 | setSender(msg.sender); 22 | return super.balanceOf(account); 23 | } 24 | 25 | function setSender(address _sender) private { 26 | sender = _sender; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/ERC20Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.4; 4 | 5 | contract ERC20Mock { 6 | mapping(address => uint256) private balances; 7 | 8 | constructor(address initialAccount, uint256 initialBalance) { 9 | mint(initialAccount, initialBalance); 10 | } 11 | 12 | /** 13 | * 14 | * @dev The `balanceOf` function should be a view function, but for testing purposes, this function is not. 15 | * This makes it easy to test non-compliant ERC-20 tokens. 16 | */ 17 | function balanceOf(address account) public virtual returns (uint256) { 18 | return balances[account]; 19 | } 20 | 21 | function mint(address account, uint256 amount) public { 22 | balances[account] += amount; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/ERCQuery.sol: -------------------------------------------------------------------------------- 1 | /** 2 | *Submitted for verification at Etherscan.io on 2021-01-12 3 | */ 4 | 5 | pragma abicoder v2; 6 | pragma solidity ^0.7.6; 7 | 8 | interface IERC20String { 9 | function symbol() external view returns (string memory); 10 | 11 | function name() external view returns (string memory); 12 | } 13 | 14 | interface IERC20Bytes32 { 15 | function symbol() external view returns (bytes32); 16 | 17 | function name() external view returns (bytes32); 18 | } 19 | 20 | contract TokenInfo { 21 | struct Info { 22 | string symbol; 23 | string name; 24 | } 25 | 26 | function getInfoBatch(address[] memory tokens) external view returns (Info[] memory infos) { 27 | Info[] memory infos = new Info[](tokens.length); 28 | for (uint8 i = 0; i < tokens.length; i++) { 29 | Info memory info; 30 | infos[i] = this.getInfo(tokens[i]); 31 | } 32 | return infos; 33 | } 34 | 35 | function getInfo(address token) external view returns (Info memory info) { 36 | // Does code exists for the token? 37 | uint32 size; 38 | assembly { 39 | size := extcodesize(token) 40 | } 41 | if (size == 0) { 42 | return info; 43 | } 44 | 45 | try this.getStringProperties(token) returns (string memory _symbol, string memory _name) { 46 | info.symbol = _symbol; 47 | info.name = _name; 48 | return info; 49 | } catch {} 50 | try this.getBytes32Properties(token) returns (string memory _symbol, string memory _name) { 51 | info.symbol = _symbol; 52 | info.name = _name; 53 | return info; 54 | } catch {} 55 | } 56 | 57 | function getStringProperties(address token) 58 | external 59 | view 60 | returns (string memory symbol, string memory name) 61 | { 62 | symbol = IERC20String(token).symbol(); 63 | name = IERC20String(token).name(); 64 | } 65 | 66 | function getBytes32Properties(address token) 67 | external 68 | view 69 | returns (string memory symbol, string memory name) 70 | { 71 | bytes32 symbolBytes32 = IERC20Bytes32(token).symbol(); 72 | bytes32 nameBytes32 = IERC20Bytes32(token).name(); 73 | symbol = bytes32ToString(symbolBytes32); 74 | name = bytes32ToString(nameBytes32); 75 | } 76 | 77 | function bytes32ToString(bytes32 _bytes32) internal pure returns (string memory) { 78 | uint8 i = 0; 79 | while (i < 32 && _bytes32[i] != 0) { 80 | i++; 81 | } 82 | bytes memory bytesArray = new bytes(i); 83 | for (i = 0; i < 32 && _bytes32[i] != 0; i++) { 84 | bytesArray[i] = _bytes32[i]; 85 | } 86 | return string(bytesArray); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/EthHelper.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.4; 3 | 4 | // @author 0age 5 | contract EthHelper { 6 | function hasCode(address addr) external view returns (bool) { 7 | uint256 size; 8 | assembly { 9 | size := extcodesize(addr) 10 | } 11 | return size > 0; 12 | } 13 | 14 | function codeSize(address addr) external view returns (uint256) { 15 | uint256 size; 16 | assembly { 17 | size := extcodesize(addr) 18 | } 19 | return size; 20 | } 21 | 22 | function code(address addr) external view returns (bytes memory) { 23 | return addr.code; 24 | } 25 | 26 | function codeHash(address addr) external view returns (bytes32) { 27 | return addr.codehash; 28 | } 29 | 30 | function balance(address addr) external view returns (uint256) { 31 | return addr.balance; 32 | } 33 | 34 | function txOrigin() external view returns (address) { 35 | return tx.origin; 36 | } 37 | 38 | function txGasPrice() external view returns (uint256) { 39 | return tx.gasprice; 40 | } 41 | 42 | function chainId() external view returns (uint256) { 43 | return block.chainid; 44 | } 45 | 46 | function blockCoinbase() external view returns (address) { 47 | return block.coinbase; 48 | } 49 | 50 | function blockDifficulty() external view returns (uint256) { 51 | return block.difficulty; 52 | } 53 | 54 | function blockGaslimit() external view returns (uint256) { 55 | return block.gaslimit; 56 | } 57 | 58 | function blockNumber() external view returns (uint256) { 59 | return block.number; 60 | } 61 | 62 | function blockTimestamp() external view returns (uint256) { 63 | return block.timestamp; 64 | } 65 | 66 | function blockHashAt(uint256 blockNumber) external view returns (bytes32) { 67 | uint256 blocksAgo = block.number - blockNumber; 68 | require( 69 | blocksAgo > 0 && blocksAgo <= 256, 70 | "EthHelper#blockHashAt: Invalid blockNumber value" 71 | ); 72 | return blockhash(blockNumber); 73 | } 74 | 75 | function blockHashFrom(uint256 blocksAgo) external view returns (bytes32) { 76 | require( 77 | blocksAgo > 0 && blocksAgo <= 256, 78 | "EthHelper#blockHashFrom: Invalid blocksAgo value" 79 | ); 80 | return blockhash(block.number - blocksAgo); 81 | } 82 | 83 | function gasleft() external view returns (uint256) { 84 | // Note: does not correct for 63/64ths rule, only useful as an approximation 85 | return gasleft(); 86 | } 87 | 88 | function not(bool a) external pure returns (bool) { 89 | return !a; 90 | } 91 | 92 | function and(bool a, bool b) external pure returns (bool) { 93 | return a && b; 94 | } 95 | 96 | function or(bool a, bool b) external pure returns (bool) { 97 | return a || b; 98 | } 99 | 100 | function add(uint256 a, uint256 b) external pure returns (uint256) { 101 | return a + b; 102 | } 103 | 104 | function sub(uint256 a, uint256 b) external pure returns (uint256) { 105 | return a - b; 106 | } 107 | 108 | function mul(uint256 a, uint256 b) external pure returns (uint256) { 109 | return a * b; 110 | } 111 | 112 | function div(uint256 a, uint256 b) external pure returns (uint256) { 113 | return a / b; 114 | } 115 | 116 | function mod(uint256 a, uint256 b) external pure returns (uint256) { 117 | return a % b; 118 | } 119 | 120 | function exp(uint256 a, uint256 b) external pure returns (uint256) { 121 | return a**b; 122 | } 123 | 124 | function addmod( 125 | uint256 x, 126 | uint256 y, 127 | uint256 k 128 | ) external pure returns (uint256) { 129 | return addmod(x, y, k); 130 | } 131 | 132 | function mulmod( 133 | uint256 x, 134 | uint256 y, 135 | uint256 k 136 | ) external pure returns (uint256) { 137 | return mulmod(x, y, k); 138 | } 139 | 140 | function and(uint256 a, uint256 b) external pure returns (uint256) { 141 | return a & b; 142 | } 143 | 144 | function or(uint256 a, uint256 b) external pure returns (uint256) { 145 | return a | b; 146 | } 147 | 148 | function xor(uint256 a, uint256 b) external pure returns (uint256) { 149 | return a ^ b; 150 | } 151 | 152 | function bitwiseNot(uint256 a) external pure returns (uint256) { 153 | return ~a; 154 | } 155 | 156 | function shl(uint256 a, uint256 b) external pure returns (uint256) { 157 | return a << b; 158 | } 159 | 160 | function shr(uint256 a, uint256 b) external pure returns (uint256) { 161 | return a >> b; 162 | } 163 | 164 | function lt(uint256 a, uint256 b) external pure returns (bool) { 165 | return a < b; 166 | } 167 | 168 | function lte(uint256 a, uint256 b) external pure returns (bool) { 169 | return a <= b; 170 | } 171 | 172 | function gt(uint256 a, uint256 b) external pure returns (bool) { 173 | return a > b; 174 | } 175 | 176 | function gte(uint256 a, uint256 b) external pure returns (bool) { 177 | return a >= b; 178 | } 179 | 180 | function eq(uint256 a, uint256 b) external pure returns (bool) { 181 | return a == b; 182 | } 183 | 184 | function ne(uint256 a, uint256 b) external pure returns (bool) { 185 | return a != b; 186 | } 187 | 188 | function and(bytes32 a, bytes32 b) external pure returns (bytes32) { 189 | return a & b; 190 | } 191 | 192 | function or(bytes32 a, bytes32 b) external pure returns (bytes32) { 193 | return a | b; 194 | } 195 | 196 | function xor(bytes32 a, bytes32 b) external pure returns (bytes32) { 197 | return a ^ b; 198 | } 199 | 200 | function bitwiseNot(bytes32 a) external pure returns (bytes32) { 201 | return ~a; 202 | } 203 | 204 | function shl(bytes32 a, uint256 b) external pure returns (bytes32) { 205 | return a << b; 206 | } 207 | 208 | function shr(bytes32 a, uint256 b) external pure returns (bytes32) { 209 | return a >> b; 210 | } 211 | 212 | function lt(bytes32 a, bytes32 b) external pure returns (bool) { 213 | return a < b; 214 | } 215 | 216 | function lte(bytes32 a, bytes32 b) external pure returns (bool) { 217 | return a <= b; 218 | } 219 | 220 | function gt(bytes32 a, bytes32 b) external pure returns (bool) { 221 | return a > b; 222 | } 223 | 224 | function gte(bytes32 a, bytes32 b) external pure returns (bool) { 225 | return a >= b; 226 | } 227 | 228 | function eq(bytes32 a, bytes32 b) external pure returns (bool) { 229 | return a == b; 230 | } 231 | 232 | function ne(bytes32 a, bytes32 b) external pure returns (bool) { 233 | return a != b; 234 | } 235 | 236 | function lt(address a, address b) external pure returns (bool) { 237 | return a < b; 238 | } 239 | 240 | function lte(address a, address b) external pure returns (bool) { 241 | return a <= b; 242 | } 243 | 244 | function gt(address a, address b) external pure returns (bool) { 245 | return a > b; 246 | } 247 | 248 | function gte(address a, address b) external pure returns (bool) { 249 | return a >= b; 250 | } 251 | 252 | function eq(address a, address b) external pure returns (bool) { 253 | return a == b; 254 | } 255 | 256 | function ne(address a, address b) external pure returns (bool) { 257 | return a != b; 258 | } 259 | 260 | function isCaller(address addr) external view returns (bool) { 261 | return msg.sender == addr; 262 | } 263 | 264 | function eq(bytes calldata a, bytes calldata b) external pure returns (bool) { 265 | return keccak256(a) == keccak256(b); 266 | } 267 | 268 | function ne(bytes calldata a, bytes calldata b) external pure returns (bool) { 269 | return keccak256(a) != keccak256(b); 270 | } 271 | 272 | function eq(string calldata a, string calldata b) external pure returns (bool) { 273 | return keccak256(bytes(a)) == keccak256(bytes(b)); 274 | } 275 | 276 | function ne(string calldata a, string calldata b) external pure returns (bool) { 277 | return keccak256(bytes(a)) != keccak256(bytes(b)); 278 | } 279 | 280 | function keccak256(bytes calldata data) external pure returns (bytes32) { 281 | return keccak256(data); 282 | } 283 | 284 | function ripemd160(bytes calldata data) external pure returns (bytes32) { 285 | return ripemd160(data); 286 | } 287 | 288 | function sha256(bytes calldata data) external pure returns (bytes32) { 289 | return sha256(data); 290 | } 291 | 292 | function ecrecover( 293 | bytes32 hash, 294 | uint8 v, 295 | bytes32 r, 296 | bytes32 s 297 | ) external pure returns (address) { 298 | return ecrecover(hash, v, r, s); 299 | } 300 | } 301 | -------------------------------------------------------------------------------- /src/GasMeterFactory.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0 <0.9.0; 2 | import "ds-test/test.sol"; 3 | 4 | // ------------------------------------------------------------------ 5 | // Test Harness 6 | // ------------------------------------------------------------------ 7 | contract Hevm { 8 | function warp(uint) public; 9 | } 10 | contract GasMeterFactory { 11 | /* 12 | A GasMeter is a contract that returns the exact value of the gas provided 13 | in any call to it. It must be writtten in bytecode directly as the solidity 14 | function dispatch code already consumes gas, so any solidity implementation 15 | will always return an incorrect result. 16 | Bytecode: 17 | --- 18 | 0x5a 0x60 0x02 0x01 0x60 0x00 0x52 0x60 0x20 0x60 0x00 0xf3 19 | GAS PUSH1 2 ADD PUSH1 0 MSTORE PUSH1 32 PUSH1 0 RETURN 20 | Initcode: 21 | --- 22 | 0x6b 0x5a 0x60 0x02 0x01 0x60 0x00 0x52 0x60 0x20 0x60 0x20 0x60 0x00 0xf3 23 | PUSH12 24 | 0x60 0x00 0x52 0x60 0x20 0x60 0x14 0xf3 25 | PUSH1 0 MSTORE PUSH1 32 PUSH1 20 RETURN 26 | */ 27 | 28 | function build() public returns (address out) { 29 | assembly { 30 | mstore(mload(0x40), 0x6b5a60020160005260206000f360005260206014f3) 31 | out := create(0, add(11, mload(0x40)), 21) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/GenericFactory.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.6.0; 2 | 3 | import "./CounterfactualFactory.sol"; 4 | 5 | contract GenericFactory is CounterfactualFactory { 6 | event NewContract(address indexed addr); 7 | 8 | function predictAddress(bytes memory _code, bytes32 _salt) public view returns (address) { 9 | return predictAddressWithCall(_code, _salt, bytes("")); 10 | } 11 | 12 | function createContract(bytes memory _code, bytes32 _salt) public returns (address) { 13 | return createContractAndCall(_code, _salt, bytes("")); 14 | } 15 | 16 | function predictAddressWithCall( 17 | bytes memory _code, 18 | bytes32 _salt, 19 | bytes memory _call 20 | ) public view returns (address) { 21 | return _predictAddress(_code, keccak256(abi.encodePacked(_salt, _call))); 22 | } 23 | 24 | function createContractAndCall( 25 | bytes memory _code, 26 | bytes32 _salt, 27 | bytes memory _call 28 | ) public returns (address) { 29 | address addr = _create2(_code, keccak256(abi.encodePacked(_salt, _call))); 30 | emit NewContract(addr); 31 | if (_call.length > 0) { 32 | // solium-disable-next-line security/no-low-level-calls 33 | (bool success, bytes memory reason) = addr.call(_call); 34 | require(success, string(reason)); 35 | } 36 | return addr; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Helpers.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8; 2 | 3 | contract Helpers { 4 | // slice string 5 | function getSlice(uint256 begin, uint256 end, string memory text) internal pure returns (string memory) { 6 | bytes memory a = new bytes(end-begin+1); 7 | for(uint i=0;i<=end-begin;i++){ 8 | a[i] = bytes(text)[i+begin-1]; 9 | } 10 | return string(a); 11 | } 12 | 13 | // convert string to uint8 (numbers 0-9) 14 | function stringToUint8(string memory numString) public pure returns(uint8) { 15 | return uint8(bytes(numString)[0])-48; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/ImmutableCreate2Factory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.15; 3 | 4 | /** 5 | * @title Immutable Create2 Contract Factory 6 | * @author 0age 7 | * @notice This contract provides a safeCreate2 function that takes a salt value 8 | * and a block of initialization code as arguments and passes them into inline 9 | * assembly. The contract prevents redeploys by maintaining a mapping of all 10 | * contracts that have already been deployed, and prevents frontrunning or other 11 | * collisions by requiring that the first 20 bytes of the salt are equal to the 12 | * address of the caller (this can be bypassed by setting the first 20 bytes to 13 | * the null address). There is also a view function that computes the address of 14 | * the contract that will be created when submitting a given salt or nonce along 15 | * with a given block of initialization code. 16 | * @dev This contract has not yet been fully tested or audited - proceed with 17 | * caution and please share any exploits or optimizations you discover. 18 | */ 19 | contract ImmutableCreate2Factory { 20 | // mapping to track which addresses have already been deployed. 21 | mapping(address => bool) private _deployed; 22 | 23 | /** 24 | * @dev Create a contract using CREATE2 by submitting a given salt or nonce 25 | * along with the initialization code for the contract. Note that the first 20 26 | * bytes of the salt must match those of the calling address, which prevents 27 | * contract creation events from being submitted by unintended parties. 28 | * @param salt bytes32 The nonce that will be passed into the CREATE2 call. 29 | * @param initializationCode bytes The initialization code that will be passed 30 | * into the CREATE2 call. 31 | * @return deploymentAddress - address of the contract that will be created, 32 | * or the null address if a contract already exists at that address. 33 | */ 34 | function safeCreate2(bytes32 salt, bytes calldata initializationCode) 35 | external 36 | payable 37 | containsCaller(salt) 38 | returns (address deploymentAddress) 39 | { 40 | // move the initialization code from calldata to memory. 41 | bytes memory initCode = initializationCode; 42 | 43 | // determine the target address for contract deployment. 44 | address targetDeploymentAddress = address( 45 | uint160( // downcast to match the address type. 46 | uint256( // convert to uint to truncate upper digits. 47 | keccak256( // compute the CREATE2 hash using 4 inputs. 48 | abi.encodePacked( // pack all inputs to the hash together. 49 | hex"ff", // start with 0xff to distinguish from RLP. 50 | address(this), // this contract will be the caller. 51 | salt, // pass in the supplied salt value. 52 | keccak256(abi.encodePacked(initCode)) // pass in the hash of initialization code. 53 | ) 54 | ) 55 | ) 56 | ) 57 | ); 58 | 59 | // ensure that a contract hasn't been previously deployed to target address. 60 | require( 61 | !_deployed[targetDeploymentAddress], 62 | "Invalid contract creation - contract has already been deployed." 63 | ); 64 | 65 | // using inline assembly: load data and length of data, then call CREATE2. 66 | assembly { 67 | // solhint-disable-line 68 | let encoded_data := add(0x20, initCode) // load initialization code. 69 | let encoded_size := mload(initCode) // load the init code's length. 70 | deploymentAddress := create2( 71 | // call CREATE2 with 4 arguments. 72 | callvalue(), // forward any attached value. 73 | encoded_data, // pass in initialization code. 74 | encoded_size, // pass in init code's length. 75 | salt // pass in the salt value. 76 | ) 77 | } 78 | 79 | // check address against target to ensure that deployment was successful. 80 | require( 81 | deploymentAddress == targetDeploymentAddress, 82 | "Failed to deploy contract using provided salt and initialization code." 83 | ); 84 | 85 | // record the deployment of the contract to prevent redeploys. 86 | _deployed[deploymentAddress] = true; 87 | } 88 | 89 | /** 90 | * @dev Compute the address of the contract that will be created when 91 | * submitting a given salt or nonce to the contract along with the contract's 92 | * initialization code. The CREATE2 address is computed in accordance with 93 | * EIP-1014, and adheres to the formula therein of 94 | * `keccak256( 0xff ++ address ++ salt ++ keccak256(init_code)))[12:]` when 95 | * performing the computation. The computed address is then checked for any 96 | * existing contract code - if so, the null address will be returned instead. 97 | * @param salt bytes32 The nonce passed into the CREATE2 address calculation. 98 | * @param initCode bytes The contract initialization code to be used. 99 | * that will be passed into the CREATE2 address calculation. 100 | * @return deploymentAddress - address of the contract that will be created, 101 | * or the null address if a contract has already been deployed to that address. 102 | */ 103 | function findCreate2Address(bytes32 salt, bytes calldata initCode) 104 | external 105 | view 106 | returns (address deploymentAddress) 107 | { 108 | // determine the address where the contract will be deployed. 109 | deploymentAddress = address( 110 | uint160( // downcast to match the address type. 111 | uint256( // convert to uint to truncate upper digits. 112 | keccak256( // compute the CREATE2 hash using 4 inputs. 113 | abi.encodePacked( // pack all inputs to the hash together. 114 | hex"ff", // start with 0xff to distinguish from RLP. 115 | address(this), // this contract will be the caller. 116 | salt, // pass in the supplied salt value. 117 | keccak256(abi.encodePacked(initCode)) // pass in the hash of initialization code. 118 | ) 119 | ) 120 | ) 121 | ) 122 | ); 123 | 124 | // return null address to signify failure if contract has been deployed. 125 | if (_deployed[deploymentAddress]) { 126 | return address(0); 127 | } 128 | } 129 | 130 | /** 131 | * @dev Compute the address of the contract that will be created when 132 | * submitting a given salt or nonce to the contract along with the keccak256 133 | * hash of the contract's initialization code. The CREATE2 address is computed 134 | * in accordance with EIP-1014, and adheres to the formula therein of 135 | * `keccak256( 0xff ++ address ++ salt ++ keccak256(init_code)))[12:]` when 136 | * performing the computation. The computed address is then checked for any 137 | * existing contract code - if so, the null address will be returned instead. 138 | * @param salt bytes32 The nonce passed into the CREATE2 address calculation. 139 | * @param initCodeHash bytes32 The keccak256 hash of the initialization code 140 | * that will be passed into the CREATE2 address calculation. 141 | * @return deploymentAddress - address of the contract that will be created, 142 | * or the null address if a contract has already been deployed to that address. 143 | */ 144 | function findCreate2AddressViaHash(bytes32 salt, bytes32 initCodeHash) 145 | external 146 | view 147 | returns (address deploymentAddress) 148 | { 149 | // determine the address where the contract will be deployed. 150 | deploymentAddress = address( 151 | uint160( // downcast to match the address type. 152 | uint256( // convert to uint to truncate upper digits. 153 | keccak256( // compute the CREATE2 hash using 4 inputs. 154 | abi.encodePacked( // pack all inputs to the hash together. 155 | hex"ff", // start with 0xff to distinguish from RLP. 156 | address(this), // this contract will be the caller. 157 | salt, // pass in the supplied salt value. 158 | initCodeHash // pass in the hash of initialization code. 159 | ) 160 | ) 161 | ) 162 | ) 163 | ); 164 | 165 | // return null address to signify failure if contract has been deployed. 166 | if (_deployed[deploymentAddress]) { 167 | return address(0); 168 | } 169 | } 170 | 171 | /** 172 | * @dev Determine if a contract has already been deployed by the factory to a 173 | * given address. 174 | * @param deploymentAddress address The contract address to check. 175 | * @return True if the contract has been deployed, false otherwise. 176 | */ 177 | function hasBeenDeployed(address deploymentAddress) external view returns (bool) { 178 | // determine if a contract has been deployed to the provided address. 179 | return _deployed[deploymentAddress]; 180 | } 181 | 182 | /** 183 | * @dev Modifier to ensure that the first 20 bytes of a submitted salt match 184 | * those of the calling account. This provides protection against the salt 185 | * being stolen by frontrunners or other attackers. The protection can also be 186 | * bypassed if desired by setting each of the first 20 bytes to zero. 187 | * @param salt bytes32 The salt value to check against the calling address. 188 | */ 189 | modifier containsCaller(bytes32 salt) { 190 | // prevent contract submissions from being stolen from tx.pool by requiring 191 | // that the first 20 bytes of the submitted salt match msg.sender. 192 | require( 193 | (address(bytes20(salt)) == msg.sender) || (bytes20(salt) == bytes20(0)), 194 | "Invalid salt - first 20 bytes of the salt must match calling address." 195 | ); 196 | _; 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /src/Introspection.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.4; 4 | 5 | contract Introspection { 6 | function implementsMethod(address _address, string memory _signature) 7 | public 8 | view 9 | returns (bool) 10 | { 11 | bytes4 _selector = bytes4(keccak256(bytes(_signature))); 12 | uint256 contractSize; 13 | assembly { 14 | contractSize := extcodesize(_address) 15 | } 16 | bytes memory code = new bytes(contractSize); 17 | assembly { 18 | extcodecopy(_address, add(code, 0x20), 0, contractSize) 19 | } 20 | uint256 ptr = 0; 21 | while (ptr < contractSize) { 22 | // PUSH4 0x000000 (selector) 23 | if (code[ptr] == 0x63) { 24 | bytes memory selectorBytes = new bytes(64); 25 | selectorBytes[0] = code[ptr + 1]; 26 | selectorBytes[1] = code[ptr + 2]; 27 | selectorBytes[2] = code[ptr + 3]; 28 | selectorBytes[3] = code[ptr + 4]; 29 | bytes4 selector = abi.decode(selectorBytes, (bytes4)); 30 | if (selector == _selector) { 31 | return true; 32 | } 33 | } 34 | ptr++; 35 | } 36 | return false; 37 | } 38 | 39 | function implementsInterface(address _address, string[] memory _interface) 40 | external 41 | view 42 | returns (bool) 43 | { 44 | for (uint256 methodIdx = 0; methodIdx < _interface.length; methodIdx++) { 45 | string memory method = _interface[methodIdx]; 46 | bool methodIsImplemented = implementsMethod(_address, method); 47 | if (!methodIsImplemented) { 48 | return false; 49 | } 50 | } 51 | return true; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/MeterMaid.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.4; 3 | 4 | interface MeterMaidInterface { 5 | function meter(address to, bytes calldata data) 6 | external 7 | returns ( 8 | uint256 gasUsed, 9 | bool ok, 10 | bytes memory returnData 11 | ); 12 | } 13 | 14 | contract MeterMaid is MeterMaidInterface { 15 | function meter(address to, bytes calldata data) 16 | external 17 | override 18 | returns ( 19 | uint256 gasUsed, 20 | bool ok, 21 | bytes memory returnData 22 | ) 23 | { 24 | uint256 initialGas = gasleft(); 25 | (ok, returnData) = to.call(data); 26 | gasUsed = initialGas - gasleft(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/PairsHelper.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.4; 4 | 5 | interface IERC20 { 6 | function allowance(address spender, address owner) external view returns (uint256); 7 | } 8 | 9 | interface IUniswapV2Factory { 10 | function getPair(address tokenA, address tokenB) external view returns (address pair); 11 | 12 | function allPairs(uint256) external view returns (address pair); 13 | 14 | function allPairsLength() external view returns (uint256); 15 | } 16 | 17 | interface IUniswapV2Router { 18 | function WETH() external pure returns (address); 19 | } 20 | 21 | interface IUniswapV2Pair { 22 | function token0() external view returns (address); 23 | 24 | function token1() external view returns (address); 25 | } 26 | 27 | interface IUniqueAddressesHelper { 28 | function uniqueAddresses(address[] memory) external view returns (address[] memory); 29 | } 30 | 31 | contract PairsHelper { 32 | address public owner; 33 | address public wethAddress; 34 | address public uniqueAddressesHelperAddress; 35 | IUniqueAddressesHelper uniqueAddressesHelper; 36 | 37 | constructor(address _wethAddress, address _uniqueAddressesHelperAddress) { 38 | owner = msg.sender; 39 | uniqueAddressesHelperAddress = _uniqueAddressesHelperAddress; 40 | uniqueAddressesHelper = IUniqueAddressesHelper(uniqueAddressesHelperAddress); 41 | wethAddress = _wethAddress; 42 | } 43 | 44 | function pairsLength(address factoryAddress) public view returns (uint256) { 45 | return IUniswapV2Factory(factoryAddress).allPairsLength(); 46 | } 47 | 48 | function pagesLength( 49 | address factoryAddress, 50 | uint256 pageSize, 51 | uint256 offset 52 | ) public view returns (uint256) { 53 | uint256 _pairsLength = pairsLength(factoryAddress); 54 | uint256 _pagesLength = (_pairsLength - offset) / pageSize; 55 | return _pagesLength + 1; 56 | } 57 | 58 | function pagesLength(address factoryAddress, uint256 pageSize) public view returns (uint256) { 59 | uint256 _pairsLength = pairsLength(factoryAddress); 60 | uint256 _pagesLength = _pairsLength / pageSize; 61 | return _pagesLength + 1; 62 | } 63 | 64 | function pairsAddresses( 65 | address factoryAddress, 66 | uint256 pageSize, 67 | uint256 pageNbr, 68 | uint256 offset 69 | ) public view returns (address[] memory) { 70 | uint256 _pairsLength = pairsLength(factoryAddress); 71 | uint256 startIdx = (pageNbr * pageSize) + offset; 72 | uint256 endIdx = startIdx + pageSize; 73 | if (endIdx > _pairsLength - 1) { 74 | endIdx = _pairsLength - 1; 75 | } 76 | address[] memory _pairsAddresses = new address[](_pairsLength); 77 | uint256 pairIdx; 78 | for (; pairIdx + startIdx <= endIdx; pairIdx++) { 79 | address pairAddress = IUniswapV2Factory(factoryAddress).allPairs(pairIdx + startIdx); 80 | _pairsAddresses[pairIdx] = pairAddress; 81 | } 82 | bytes memory pairsAddressesEncoded = abi.encode(_pairsAddresses); 83 | assembly { 84 | mstore(add(pairsAddressesEncoded, 0x40), pairIdx) 85 | } 86 | _pairsAddresses = abi.decode(pairsAddressesEncoded, (address[])); 87 | return _pairsAddresses; 88 | } 89 | 90 | function tokensAddresses( 91 | address factoryAddress, 92 | uint256 pageSize, 93 | uint256 pageNbr, 94 | uint256 offset 95 | ) public view returns (address[] memory) { 96 | address[] memory _pairsAddresses = pairsAddresses( 97 | factoryAddress, 98 | pageSize, 99 | pageNbr, 100 | offset 101 | ); 102 | uint256 _pairsLength = _pairsAddresses.length; 103 | uint256 maxTokensLength = (_pairsLength * 2) + 1; 104 | address[] memory _tokensAddresses = new address[](maxTokensLength); 105 | 106 | if (_pairsLength == 0) { 107 | return new address[](0); 108 | } 109 | _tokensAddresses[0] = wethAddress; 110 | uint256 tokenIdx = 1; 111 | for (uint256 pairIdx = 0; pairIdx < _pairsLength; pairIdx++) { 112 | address pairAddress = _pairsAddresses[pairIdx]; 113 | IUniswapV2Pair pair = IUniswapV2Pair(pairAddress); 114 | address token0Address = pair.token0(); 115 | address token1Address = pair.token1(); 116 | if (token0Address != wethAddress) { 117 | _tokensAddresses[tokenIdx] = token0Address; 118 | tokenIdx++; 119 | } 120 | if (token1Address != wethAddress) { 121 | _tokensAddresses[tokenIdx] = token1Address; 122 | tokenIdx++; 123 | } 124 | } 125 | bytes memory tokensAddressesEncoded = abi.encode(_tokensAddresses); 126 | assembly { 127 | mstore(add(tokensAddressesEncoded, 0x40), tokenIdx) 128 | } 129 | _tokensAddresses = uniqueAddressesHelper.uniqueAddresses( 130 | abi.decode(tokensAddressesEncoded, (address[])) 131 | ); 132 | return _tokensAddresses; 133 | } 134 | 135 | function tokensAddresses( 136 | address factoryAddress, 137 | uint256 pageSize, 138 | uint256 pageNbr 139 | ) public view returns (address[] memory) { 140 | return tokensAddresses(factoryAddress, pageSize, pageNbr, 0); 141 | } 142 | 143 | function tokensAddresses(address factoryAddress) public view returns (address[] memory) { 144 | uint256 _pairsLength = pairsLength(factoryAddress); 145 | return tokensAddresses(factoryAddress, _pairsLength, 0, 0); 146 | } 147 | 148 | function pairsAddresses( 149 | address factoryAddress, 150 | uint256 pageSize, 151 | uint256 pageNbr 152 | ) public view returns (address[] memory) { 153 | return pairsAddresses(factoryAddress, pageSize, pageNbr, 0); 154 | } 155 | 156 | function pairsAddresses(address factoryAddress) public view returns (address[] memory) { 157 | uint256 _pairsLength = pairsLength(factoryAddress); 158 | return pairsAddresses(factoryAddress, _pairsLength, 0, 0); 159 | } 160 | 161 | function updateSlot(bytes32 slot, bytes32 value) external { 162 | require(msg.sender == owner); 163 | assembly { 164 | sstore(slot, value) 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /src/PhonyUser.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.8.0; 2 | 3 | contract PhonyUser { 4 | function tryCall(address target, bytes memory data) 5 | public 6 | virtual 7 | returns (bool success, bytes memory returnData) 8 | { 9 | (success, returnData) = target.call(data); 10 | } 11 | 12 | function call(address target, bytes memory data) 13 | public 14 | virtual 15 | returns (bytes memory returnData) 16 | { 17 | bool success; 18 | (success, returnData) = target.call(data); 19 | 20 | if (!success) { 21 | if (returnData.length > 0) { 22 | assembly { 23 | let returnDataSize := mload(returnData) 24 | revert(add(32, returnData), returnDataSize) 25 | } 26 | } else { 27 | revert("REVERT_NULL_MESSAGE"); 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/ReplayProtection.sol: -------------------------------------------------------------------------------- 1 | /// SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /// @title ReplayProtection 6 | /// @author Amxx 7 | // @source https://github.com/Amxx/EIP3074-Invokers/blob/master/contracts/utils/ReplayProtection.sol 8 | 9 | library ReplayProtection { 10 | struct Nonces { 11 | mapping(address => uint256) _data; 12 | } 13 | 14 | function getNonce(Nonces storage nonces, address from) internal view returns (uint256) { 15 | return nonces._data[from]; 16 | } 17 | 18 | function verifyAndConsumeNonce( 19 | Nonces storage nonces, 20 | address owner, 21 | uint256 idx 22 | ) internal returns (bool) { 23 | return idx == nonces._data[owner]++; 24 | } 25 | 26 | struct MultiNonces { 27 | mapping(address => mapping(uint256 => uint256)) _data; 28 | } 29 | 30 | function getNonce(MultiNonces storage nonces, address from) internal view returns (uint256) { 31 | return nonces._data[from][0]; 32 | } 33 | 34 | function getNonce( 35 | MultiNonces storage nonces, 36 | address from, 37 | uint256 timeline 38 | ) internal view returns (uint256) { 39 | return nonces._data[from][timeline]; 40 | } 41 | 42 | function verifyAndConsumeNonce( 43 | MultiNonces storage nonces, 44 | address owner, 45 | uint256 idx 46 | ) internal returns (bool) { 47 | return idx % (1 << 128) == nonces._data[owner][idx >> 128]++; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/SelectorsAndSignatures.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.7; 3 | 4 | // source: twitter.com/PatrickAlphaC/status/1517156283215802368 5 | 6 | /// @title SelectorsAndSignatures 7 | contract SelectorsAndSignatures { 8 | address public s_someAddress; 9 | uint256 public s_amount; 10 | 11 | function getSelectorOne() public pure returns (bytes4 selector) { 12 | selector = bytes4(keccak256(bytes("transfer(address, uint256)"))); 13 | } 14 | 15 | function getSelectorTwo() public view returns (bytes4 selector) { 16 | bytes memory functionCallData = abi.encodeWithSignature( 17 | "transfer(address, uint256)", 18 | address(this), 19 | 123 20 | ); 21 | 22 | selector = bytes4( 23 | bytes.concat( 24 | functionCallData[0], 25 | functionCallData[1], 26 | functionCallData[2], 27 | functionCallData[3] 28 | ) 29 | ); 30 | } 31 | 32 | function getCallData() public view returns (bytes memory) { 33 | return abi.encodeWithSignature("transfer(address, uint256)", address(this), 123); 34 | } 35 | 36 | function getSelectorThree(bytes calldata functionCallData) 37 | public 38 | pure 39 | returns (bytes4 selector) 40 | { 41 | // offset is a special attribute of calldata 42 | assembly { 43 | selector := calldataload(functionCallData.offset) 44 | } 45 | } 46 | 47 | function transfer(address someAddress, uint256 amount) public { 48 | // Some code 49 | S_someAddress = someAddress; 50 | S_amount = amount; 51 | } 52 | 53 | function getSelectorFour() public pure returns (bytes4 selector) { 54 | return this.transfer.selector; 55 | } 56 | 57 | function getSignatureOne() public pure returns (string memory) { 58 | return "transfer(address, uint256)"; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/TokenMetadata.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.2; 4 | 5 | interface IERC20 { 6 | function decimals() external view returns (uint8); 7 | 8 | function symbol() external view returns (string memory); 9 | 10 | function name() external view returns (string memory); 11 | 12 | function balanceOf(address account) external view returns (uint256); 13 | 14 | function allowance(address spender, address owner) external view returns (uint256); 15 | } 16 | 17 | interface IOracle { 18 | function getNormalizedValueUsdc( 19 | address tokenAddress, 20 | uint256 amount, 21 | uint256 price 22 | ) external view returns (uint256); 23 | 24 | function getPriceUsdcRecommended(address tokenAddress) external view returns (uint256); 25 | } 26 | 27 | /** 28 | * Static token data 29 | */ 30 | struct TokenMetadata { 31 | address id; // Token address 32 | string name; // Token name 33 | string symbol; // Token symbol 34 | uint8 decimals; // Token decimals 35 | } 36 | 37 | contract BalancesHelper { 38 | address public owner; // Owner can update storage slots 39 | address public oracleAddress; // Oracle address 40 | 41 | struct TokenBalance { 42 | address tokenId; // Token address 43 | uint256 priceUsdc; // Token price in USDC (6 decimals) 44 | uint256 balance; // Token balance in underlying token 45 | uint256 balanceUsdc; // Token balance value in USDC (6 decimals) 46 | } 47 | 48 | struct TokenPrice { 49 | address tokenId; // Token address 50 | uint256 priceUsdc; // Token price in USDC (6 decimals) 51 | } 52 | 53 | constructor(address _oracleAddress) { 54 | owner = msg.sender; 55 | oracleAddress = _oracleAddress; 56 | } 57 | 58 | /** 59 | * Fetch token balances given an array of token addresses and account address 60 | */ 61 | function tokensBalances(address accountAddress, address[] memory tokensAddresses) 62 | public 63 | view 64 | returns (TokenBalance[] memory) 65 | { 66 | TokenBalance[] memory _tokensBalances = new TokenBalance[](tokensAddresses.length); 67 | for (uint256 tokenIdx = 0; tokenIdx < tokensAddresses.length; tokenIdx++) { 68 | address tokenAddress = tokensAddresses[tokenIdx]; 69 | IERC20 token = IERC20(tokenAddress); 70 | uint256 balance = token.balanceOf(accountAddress); 71 | uint256 priceUsdc = IOracle(oracleAddress).getPriceUsdcRecommended(tokenAddress); 72 | uint256 balanceUsdc = IOracle(oracleAddress).getNormalizedValueUsdc( 73 | tokenAddress, 74 | balance, 75 | priceUsdc 76 | ); 77 | 78 | _tokensBalances[tokenIdx] = TokenBalance({ 79 | tokenId: tokenAddress, 80 | priceUsdc: priceUsdc, 81 | balance: balance, 82 | balanceUsdc: balanceUsdc 83 | }); 84 | } 85 | return _tokensBalances; 86 | } 87 | 88 | /** 89 | * Fetch token prices given an array of token addresses 90 | */ 91 | function tokensPrices(address[] memory tokensAddresses) 92 | public 93 | view 94 | returns (TokenPrice[] memory) 95 | { 96 | TokenPrice[] memory _tokensPrices = new TokenPrice[](tokensAddresses.length); 97 | for (uint256 tokenIdx = 0; tokenIdx < tokensAddresses.length; tokenIdx++) { 98 | address tokenAddress = tokensAddresses[tokenIdx]; 99 | _tokensPrices[tokenIdx] = TokenPrice({ 100 | tokenId: tokenAddress, 101 | priceUsdc: IOracle(oracleAddress).getPriceUsdcRecommended(tokenAddress) 102 | }); 103 | } 104 | return _tokensPrices; 105 | } 106 | 107 | /** 108 | * Fetch basic static token metadata 109 | */ 110 | function tokensMetadata(address[] memory tokensAddresses) 111 | public 112 | view 113 | returns (TokenMetadata[] memory) 114 | { 115 | TokenMetadata[] memory _tokensMetadata = new TokenMetadata[](tokensAddresses.length); 116 | for (uint256 tokenIdx = 0; tokenIdx < tokensAddresses.length; tokenIdx++) { 117 | address tokenAddress = tokensAddresses[tokenIdx]; 118 | IERC20 _token = IERC20(tokenAddress); 119 | _tokensMetadata[tokenIdx] = TokenMetadata({ 120 | id: tokenAddress, 121 | name: _token.name(), 122 | symbol: _token.symbol(), 123 | decimals: _token.decimals() 124 | }); 125 | } 126 | return _tokensMetadata; 127 | } 128 | 129 | function updateSlot(bytes32 slot, bytes32 value) external { 130 | require(msg.sender == owner); 131 | assembly { 132 | sstore(slot, value) 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/UniswapV3/FixedMath.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0-only 2 | pragma solidity 0.8.11; 3 | 4 | /// @title Fixed point arithmetic library 5 | /// @author Taken from https://github.com/Rari-Capital/solmate/blob/main/src/utils/FixedPointMathLib.sol 6 | library FixedMath { 7 | uint256 internal constant WAD = 1e18; 8 | uint256 internal constant RAY = 1e27; 9 | 10 | function fmul( 11 | uint256 x, 12 | uint256 y, 13 | uint256 baseUnit 14 | ) internal pure returns (uint256) { 15 | return mulDivDown(x, y, baseUnit); // Equivalent to (x * y) / baseUnit rounded down. 16 | } 17 | 18 | function fmul(uint256 x, uint256 y) internal pure returns (uint256) { 19 | return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down. 20 | } 21 | 22 | function fmulUp( 23 | uint256 x, 24 | uint256 y, 25 | uint256 baseUnit 26 | ) internal pure returns (uint256) { 27 | return mulDivUp(x, y, baseUnit); // Equivalent to (x * y) / baseUnit rounded up. 28 | } 29 | 30 | function fmulUp(uint256 x, uint256 y) internal pure returns (uint256) { 31 | return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up. 32 | } 33 | 34 | function fdiv( 35 | uint256 x, 36 | uint256 y, 37 | uint256 baseUnit 38 | ) internal pure returns (uint256) { 39 | return mulDivDown(x, baseUnit, y); // Equivalent to (x * baseUnit) / y rounded down. 40 | } 41 | 42 | function fdiv(uint256 x, uint256 y) internal pure returns (uint256) { 43 | return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down. 44 | } 45 | 46 | function fdivUp( 47 | uint256 x, 48 | uint256 y, 49 | uint256 baseUnit 50 | ) internal pure returns (uint256) { 51 | return mulDivUp(x, baseUnit, y); // Equivalent to (x * baseUnit) / y rounded up. 52 | } 53 | 54 | function fdivUp(uint256 x, uint256 y) internal pure returns (uint256) { 55 | return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up. 56 | } 57 | 58 | function mulDivDown( 59 | uint256 x, 60 | uint256 y, 61 | uint256 denominator 62 | ) internal pure returns (uint256 z) { 63 | assembly { 64 | // Store x * y in z for now. 65 | z := mul(x, y) 66 | 67 | // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y)) 68 | if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) { 69 | revert(0, 0) 70 | } 71 | 72 | // Divide z by the denominator. 73 | z := div(z, denominator) 74 | } 75 | } 76 | 77 | function mulDivUp( 78 | uint256 x, 79 | uint256 y, 80 | uint256 denominator 81 | ) internal pure returns (uint256 z) { 82 | assembly { 83 | // Store x * y in z for now. 84 | z := mul(x, y) 85 | 86 | // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y)) 87 | if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) { 88 | revert(0, 0) 89 | } 90 | 91 | // First, divide z - 1 by the denominator and add 1. 92 | // We allow z - 1 to underflow if z is 0, because we multiply the 93 | // end result by 0 if z is zero, ensuring we return 0 if z is zero. 94 | z := mul(iszero(iszero(z)), add(div(sub(z, 1), denominator), 1)) 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/UniswapV3/MockUniSwapRouterV3.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.11; 2 | 3 | import { ERC20 } from "@rari-capital/solmate/src/tokens/ERC20.sol"; 4 | import { FixedMath } from "./FixedMath.sol"; 5 | 6 | /// Taken from https://github.com/xtokenmarket/xalpha/blob/main/contracts/mock/MockUniswapV3Router.sol 7 | 8 | contract MockUniSwapRouterV3 { 9 | using FixedMath for uint256; 10 | 11 | uint256 public constant EXCHANGE_RATE = 0.95e18; 12 | 13 | struct ExactInputSingleParams { 14 | address tokenIn; 15 | address tokenOut; 16 | uint24 fee; 17 | address recipient; 18 | uint256 deadline; 19 | uint256 amountIn; 20 | uint256 amountOutMinimum; 21 | uint160 sqrtPriceLimitX96; 22 | } 23 | 24 | function exactInputSingle(ExactInputSingleParams calldata params) 25 | external 26 | payable 27 | returns (uint256) 28 | { 29 | ERC20(params.tokenIn).transferFrom(msg.sender, address(this), params.amountIn); 30 | 31 | uint256 amountOut = (params.amountIn).fmul( 32 | EXCHANGE_RATE, 33 | 10**ERC20(params.tokenIn).decimals() 34 | ); 35 | require(amountOut >= params.amountOutMinimum, "amountOutMin invariant failed"); 36 | 37 | ERC20(params.tokenOut).transfer(params.recipient, amountOut); 38 | return amountOut; 39 | } 40 | 41 | receive() external payable {} 42 | } 43 | -------------------------------------------------------------------------------- /src/UniswapV3/MockUniV3Pool.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.11; 2 | 3 | // External references 4 | import { ERC20 } from "@rari-capital/solmate/src/tokens/ERC20.sol"; 5 | 6 | contract MockUniV3Pool { 7 | function initialize(uint160 sqrtPriceX96) external {} 8 | 9 | function observe(uint32[] calldata secondsAgos) 10 | external 11 | view 12 | returns ( 13 | int56[] memory tickCumulatives, 14 | uint160[] memory secondsPerLiquidityCumulativeX128s 15 | ) 16 | { 17 | tickCumulatives = new int56[](2); 18 | secondsPerLiquidityCumulativeX128s = new uint160[](2); 19 | tickCumulatives[0] = type(int56).max; 20 | tickCumulatives[1] = type(int56).max; 21 | secondsPerLiquidityCumulativeX128s[0] = type(uint160).max; 22 | secondsPerLiquidityCumulativeX128s[1] = type(uint160).max; 23 | } 24 | } 25 | 26 | contract MockUniFactory { 27 | mapping(address => mapping(address => mapping(uint24 => address))) public getPool; 28 | 29 | function createPool( 30 | address tokenA, 31 | address tokenB, 32 | uint24 fee 33 | ) external returns (address pool) { 34 | require(tokenA != tokenB); 35 | (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); 36 | require(token0 != address(0)); 37 | require(getPool[token0][token1][fee] == address(0)); 38 | pool = address(new MockUniV3Pool()); 39 | getPool[token0][token1][fee] = pool; 40 | // populate mapping in the reverse direction, deliberate choice to avoid the cost of comparing addresses 41 | getPool[token1][token0][fee] = pool; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/WalletSummarizer.sol: -------------------------------------------------------------------------------- 1 | /// SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.4; 3 | 4 | struct Account { 5 | uint256 etherBalance; 6 | TokenSummary[] tokenSummaries; 7 | } 8 | 9 | struct TokenQuery { 10 | ERC20Interface token; 11 | address[] spenders; 12 | } 13 | 14 | struct TokenSummary { 15 | bool balanceCheckSuccess; 16 | uint256 balance; 17 | AllowanceCheck[] allowances; 18 | } 19 | 20 | struct AllowanceCheck { 21 | bool allowanceCheckSuccess; 22 | uint256 allowance; 23 | } 24 | 25 | interface ERC20Interface { 26 | function balanceOf(address account) external view returns (uint256); 27 | 28 | function allowance(address owner, address spender) external view returns (uint256); 29 | } 30 | 31 | interface WalletSummarizerInterface { 32 | function summarize(TokenQuery[] calldata tokenQueries) 33 | external 34 | view 35 | returns (Account memory accountSummary); 36 | 37 | function summarizeAccounts(TokenQuery[] calldata tokenQueries, address[] calldata accounts) 38 | external 39 | view 40 | returns (Account[] memory accountSummaries); 41 | } 42 | 43 | /// @notice Quickly check the Ether balance, as well as the balance of each 44 | /// supplied ERC20 token and a set of approved allowances, for an account or a 45 | /// collection of accounts. 46 | /// @author 0age 47 | contract WalletSummarizer is WalletSummarizerInterface { 48 | function summarize(TokenQuery[] calldata tokenQueries) 49 | external 50 | view 51 | override 52 | returns (Account memory) 53 | { 54 | Account memory accountSummary; 55 | bool success; 56 | bytes memory returnData; 57 | 58 | TokenSummary[] memory tokenSummaries = new TokenSummary[](tokenQueries.length); 59 | 60 | for (uint256 i = 0; i < tokenQueries.length; i++) { 61 | TokenSummary memory tokenSummary; 62 | TokenQuery memory tokenQuery = tokenQueries[i]; 63 | ERC20Interface token = tokenQuery.token; 64 | (success, returnData) = address(token).staticcall{ gas: gasleft() / 4 }( 65 | abi.encodeWithSelector(token.balanceOf.selector, msg.sender) 66 | ); 67 | 68 | if (success && returnData.length >= 32) { 69 | tokenSummary.balanceCheckSuccess = true; 70 | tokenSummary.balance = abi.decode(returnData, (uint256)); 71 | } 72 | 73 | address[] memory spenders = tokenQuery.spenders; 74 | AllowanceCheck[] memory allowances = new AllowanceCheck[](spenders.length); 75 | for (uint256 j = 0; j < spenders.length; j++) { 76 | AllowanceCheck memory allowanceCheck; 77 | address spender = spenders[j]; 78 | (success, returnData) = address(token).staticcall{ gas: gasleft() / 4 }( 79 | abi.encodeWithSelector(token.allowance.selector, msg.sender, spender) 80 | ); 81 | 82 | if (success && returnData.length >= 32) { 83 | allowanceCheck.allowanceCheckSuccess = true; 84 | allowanceCheck.allowance = abi.decode(returnData, (uint256)); 85 | } 86 | allowances[j] = allowanceCheck; 87 | } 88 | 89 | tokenSummary.allowances = allowances; 90 | 91 | tokenSummaries[i] = tokenSummary; 92 | } 93 | 94 | accountSummary.etherBalance = msg.sender.balance; 95 | accountSummary.tokenSummaries = tokenSummaries; 96 | 97 | return accountSummary; 98 | } 99 | 100 | function summarizeAccounts(TokenQuery[] calldata tokenQueries, address[] calldata accounts) 101 | external 102 | view 103 | override 104 | returns (Account[] memory) 105 | { 106 | Account[] memory accountSummaries = new Account[](accounts.length); 107 | 108 | bool success; 109 | bytes memory returnData; 110 | for (uint256 i = 0; i < accounts.length; i++) { 111 | address account = accounts[i]; 112 | 113 | TokenSummary[] memory tokenSummaries = new TokenSummary[](tokenQueries.length); 114 | 115 | for (uint256 j = 0; j < tokenQueries.length; j++) { 116 | TokenSummary memory tokenSummary; 117 | TokenQuery memory tokenQuery = tokenQueries[j]; 118 | ERC20Interface token = tokenQuery.token; 119 | (success, returnData) = address(token).staticcall{ gas: gasleft() / 4 }( 120 | abi.encodeWithSelector(token.balanceOf.selector, account) 121 | ); 122 | 123 | if (success && returnData.length >= 32) { 124 | tokenSummary.balanceCheckSuccess = true; 125 | tokenSummary.balance = abi.decode(returnData, (uint256)); 126 | } 127 | 128 | address[] memory spenders = tokenQuery.spenders; 129 | AllowanceCheck[] memory allowances = new AllowanceCheck[](spenders.length); 130 | for (uint256 k = 0; k < spenders.length; k++) { 131 | AllowanceCheck memory allowanceCheck; 132 | address spender = spenders[k]; 133 | (success, returnData) = address(token).staticcall{ gas: gasleft() / 4 }( 134 | abi.encodeWithSelector(token.allowance.selector, account, spender) 135 | ); 136 | 137 | if (success && returnData.length >= 32) { 138 | allowanceCheck.allowanceCheckSuccess = true; 139 | allowanceCheck.allowance = abi.decode(returnData, (uint256)); 140 | } 141 | allowances[k] = allowanceCheck; 142 | } 143 | 144 | tokenSummary.allowances = allowances; 145 | 146 | tokenSummaries[j] = tokenSummary; 147 | } 148 | 149 | accountSummaries[i].etherBalance = account.balance; 150 | accountSummaries[i].tokenSummaries = tokenSummaries; 151 | } 152 | 153 | return accountSummaries; 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/getInterface.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.4; 2 | 3 | function getInterface(string[] memory signatures) public pure returns (bytes4 interfaceId) { 4 | for (uint256 i = 0; i < signatures.length; i++) { 5 | interfaceId ^= bytes4(keccak256(bytes(signatures[i]))); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/test/TestUtils.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-identifier: MPL-2.0 2 | pragma solidity ^0.8.4; 3 | 4 | /// @title TestUtils 5 | contract TestUtils { 6 | function uint2str(uint _i) internal pure returns (string memory _uintAsString) { 7 | if (_i == 0) { 8 | return "0"; 9 | } 10 | uint j = _i; 11 | uint len; 12 | while (j != 0) { 13 | len++; 14 | j /= 10; 15 | } 16 | bytes memory bstr = new bytes(len); 17 | uint k = len; 18 | while (_i != 0) { 19 | k = k-1; 20 | uint8 temp = (48 + uint8(_i - _i / 10 * 10)); 21 | bytes1 b1 = bytes1(temp); 22 | bstr[k] = b1; 23 | _i /= 10; 24 | } 25 | return string(bstr); 26 | } 27 | function bytesToBytes32(bytes memory b, uint offset) private pure returns (bytes32) { 28 | bytes32 out; 29 | 30 | for (uint i = 0; i < 32; i++) { 31 | out |= bytes32(b[offset + i] & 0xFF) >> (i * 8); 32 | } 33 | return out; 34 | } 35 | 36 | function min(uint x, uint y) internal returns (uint) { 37 | if (x < y) return x; 38 | return y; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/test/oops.lib.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.15; 2 | library oops { 3 | function test(bytes calldata testData_) 4 | public 5 | pure 6 | returns (bytes memory testReturn) 7 | { 8 | assembly { 9 | let ptr := mload(0x40) 10 | calldatacopy(ptr, testData_.offset, testData_.length) 11 | mstore(testReturn, mload(ptr)) 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/utils/Create.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.7.0 (utils/Create.sol) 3 | // source: https://github.com/pcaversaccio/openzeppelin-contracts/blob/6ddeaf9f70871ba3d8d1e6eaf4148f35a2a7c64c/contracts/utils/Create.sol 4 | pragma solidity ^0.8.4; 5 | 6 | import "./errors.sol"; 7 | 8 | /** 9 | * @dev Helper smart contract to make easier and safer usage of the `CREATE` EVM opcode. 10 | */ 11 | 12 | library Create { 13 | /** 14 | * @dev Deploys a contract using `CREATE`. The address where the contract 15 | * will be deployed can be known computed via {computeAddress}. 16 | * @param amount The value in wei to send to the new account. 17 | * If `amount` is non-zero, `bytecode` must have a `payable` constructor. 18 | * @param bytecode The creation bytecode. 19 | * 20 | * The bytecode for a contract can be obtained from Solidity with 21 | * `type(contractName).creationCode`. 22 | * 23 | * Requirements: 24 | * 25 | * - `bytecode` must not be empty. 26 | * - the factory must have a balance of at least `amount`. 27 | * - if `amount` is non-zero, `bytecode` must have a `payable` constructor. 28 | */ 29 | function deploy(uint256 amount, bytes memory bytecode) internal returns (address) { 30 | address addr; 31 | if (address(this).balance < amount) revert InsufficientBalance(address(this)); 32 | if (bytecode.length == 0) revert ZeroBytecodeLength(address(this)); 33 | /// @solidity memory-safe-assembly 34 | assembly { 35 | addr := create(amount, add(bytecode, 0x20), mload(bytecode)) 36 | } 37 | if (addr == address(0)) revert Failed(address(this)); 38 | return addr; 39 | } 40 | 41 | /** 42 | * @dev Returns the address where a contract will be stored if deployed via {deploy}. 43 | * For the specification of the Recursive Length Prefix (RLP) encoding scheme, please 44 | * refer to p. 19 of the Ethereum Yellow Paper (https://ethereum.github.io/yellowpaper/paper.pdf) 45 | * and the Ethereum Wiki (https://eth.wiki/fundamentals/rlp). For further insights also, see the 46 | * following issue: https://github.com/Rari-Capital/solmate/issues/207. 47 | * 48 | * Based on the EIP-161 (https://github.com/ethereum/EIPs/blob/master/EIPS/eip-161.md) specification, 49 | * all contract accounts on the Ethereum mainnet are initiated with `nonce = 1`. 50 | * Thus, the first contract address created by another contract is calculated with a non-zero nonce. 51 | */ 52 | // prettier-ignore 53 | function computeAddress(address addr, uint256 nonce) internal pure returns (address) { 54 | bytes memory data; 55 | bytes1 len = bytes1(0x94); 56 | 57 | if (nonce == 0x00) data = abi.encodePacked(bytes1(0xd6), len, addr, bytes1(0x80)); 58 | else if (nonce <= 0x7f) data = abi.encodePacked(bytes1(0xd6), len, addr, uint8(nonce)); 59 | else if (nonce <= type(uint8).max) data = abi.encodePacked(bytes1(0xd7), len, addr, bytes1(0x81), uint8(nonce)); 60 | else if (nonce <= type(uint16).max) 61 | data = abi.encodePacked(bytes1(0xd8), len, addr, bytes1(0x82), uint16(nonce)); 62 | else if (nonce <= type(uint24).max) 63 | data = abi.encodePacked(bytes1(0xd9), len, addr, bytes1(0x83), uint24(nonce)); 64 | 65 | /** 66 | * @dev In the case of `nonce > type(uint24).max`, we have the following encoding scheme: 67 | * 0xda = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ address ++ 0x84 ++ nonce) 68 | * 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex) 69 | * 0x84 = 0x80 + 0x04 (0x04 = the bytes length of the nonce, 4 bytes, in hex) 70 | */ 71 | else data = abi.encodePacked(bytes1(0xda), len, addr, bytes1(0x84), uint32(nonce)); 72 | 73 | return address(uint160(uint256(keccak256(data)))); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/utils/errors.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.7.0 (utils/errors.sol) 3 | 4 | pragma solidity ^0.8.4; 5 | 6 | /** 7 | * @dev Error that occurs when the contract creation failed. 8 | * @param emitter The contract that emits the error. 9 | */ 10 | error Failed(address emitter); 11 | 12 | /** 13 | * @dev Error that occurs when the factory contract has insufficient balance. 14 | * @param emitter The contract that emits the error. 15 | */ 16 | error InsufficientBalance(address emitter); 17 | 18 | /** 19 | * @dev Error that occurs when the bytecode length is zero. 20 | * @param emitter The contract that emits the error. 21 | */ 22 | error ZeroBytecodeLength(address emitter); 23 | --------------------------------------------------------------------------------