├── foundry ├── remappings.txt ├── lib │ ├── forge-std │ │ ├── .gitignore │ │ ├── .gitmodules │ │ ├── .github │ │ │ └── workflows │ │ │ │ └── tests.yml │ │ ├── LICENSE-MIT │ │ ├── src │ │ │ ├── test │ │ │ │ ├── StdError.t.sol │ │ │ │ ├── StdCheats.t.sol │ │ │ │ ├── StdMath.t.sol │ │ │ │ ├── StdStorage.t.sol │ │ │ │ └── StdAssertions.t.sol │ │ │ └── Vm.sol │ │ ├── README.md │ │ └── LICENSE-APACHE │ └── ds-test │ │ ├── .gitignore │ │ ├── default.nix │ │ ├── Makefile │ │ ├── demo │ │ └── demo.sol │ │ └── src │ │ └── test.sol ├── foundry.toml └── src │ ├── test │ └── BasicTest.t.sol │ └── BasicToken.sol ├── .DS_Store ├── .gitattributes ├── .gitmodules ├── .gitignore ├── app.js ├── ofac-eth-list.json ├── api ├── cryptoCompareApi.js ├── fbBlocks.js ├── coingeckoApi.js ├── kyberApi.js └── oneInchQuote.js ├── hardhat ├── contracts │ └── YourContract.sol ├── hardhat.config.js ├── findVerifiedContracts.js ├── findVanityAddress.js ├── findVulContracts.js └── findUniswapClones.js ├── package.json ├── token ├── findToken.js ├── fetchPools.js ├── fetchTokens.js └── fetchMarketPairs.js ├── util ├── tokensnifferScrapper.js ├── etherscanScrapper.js └── 4byteEventsApi.js ├── ABIEvents.js ├── trxReceipts.js ├── cryptoPunksTxs.js ├── mpoolPendingTxs.js ├── gasPrices.js ├── ABILogs.js ├── uniswapV2SubGraph.js ├── README.md ├── liquidations ├── findAaveV2Txs.js └── findUniswapV3Txs.js ├── chainlinkPrices.js └── findFlashLoanTxs.js /foundry/remappings.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /foundry/lib/forge-std/.gitignore: -------------------------------------------------------------------------------- 1 | cache/ 2 | out/ 3 | -------------------------------------------------------------------------------- /foundry/lib/ds-test/.gitignore: -------------------------------------------------------------------------------- 1 | /.dapple 2 | /build 3 | /out 4 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xjjda22/scripts/HEAD/.DS_Store -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /foundry/lib/ds-test/default.nix: -------------------------------------------------------------------------------- 1 | { solidityPackage, dappsys }: solidityPackage { 2 | name = "ds-test"; 3 | src = ./src; 4 | } 5 | -------------------------------------------------------------------------------- /foundry/lib/forge-std/.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/ds-test"] 2 | path = lib/ds-test 3 | url = https://github.com/dapphub/ds-test 4 | -------------------------------------------------------------------------------- /foundry/foundry.toml: -------------------------------------------------------------------------------- 1 | [default] 2 | src = 'src' 3 | out = 'out' 4 | libs = ['lib'] 5 | remappings = [ 6 | '@ds-test/=lib/ds-test/src/', 7 | '@forge-std/=lib/forge-std/src/', 8 | '@openzeppelin/=lib/openzeppelin-contracts/contracts/', 9 | ] 10 | 11 | # See more config options https://github.com/gakonst/foundry/tree/master/config -------------------------------------------------------------------------------- /foundry/lib/ds-test/Makefile: -------------------------------------------------------------------------------- 1 | all:; dapp build 2 | 3 | test: 4 | -dapp --use solc:0.4.23 build 5 | -dapp --use solc:0.4.26 build 6 | -dapp --use solc:0.5.17 build 7 | -dapp --use solc:0.6.12 build 8 | -dapp --use solc:0.7.5 build 9 | 10 | demo: 11 | DAPP_SRC=demo dapp --use solc:0.7.5 build 12 | -hevm dapp-test --verbose 3 13 | 14 | .PHONY: test demo 15 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "foundry/lib/openzeppelin-contracts"] 2 | path = foundry/lib/openzeppelin-contracts 3 | url = https://github.com/openzeppelin/openzeppelin-contracts 4 | [submodule "foundry/lib/ds-test"] 5 | path = foundry/lib/ds-test 6 | url = https://github.com/dapphub/ds-test 7 | [submodule "foundry/lib/forge-std"] 8 | path = foundry/lib/forge-std 9 | url = https://github.com/foundry-rs/forge-std 10 | -------------------------------------------------------------------------------- /foundry/lib/forge-std/.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | check: 6 | name: Foundry project 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | with: 11 | submodules: recursive 12 | 13 | - name: Install Foundry 14 | uses: onbjerg/foundry-toolchain@v1 15 | with: 16 | version: nightly 17 | 18 | - name: Install dependencies 19 | run: forge install 20 | - name: Run tests 21 | run: forge test -vvv 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store* 2 | /node_modules 3 | /build 4 | .vscode 5 | .env* 6 | yarn.lock 7 | 8 | /json 9 | /api/json 10 | /util/json 11 | /token/json 12 | /liquidations/json 13 | 14 | /hardhat/* 15 | /hardhat/artifacts* 16 | /hardhat/cache* 17 | /hardhat/mnemonic* 18 | /hardhat/json* 19 | 20 | foundry/cache* 21 | foundry/out* 22 | foundry/.gas-snapshot 23 | 24 | # yarn / eslint 25 | .yarn/cache 26 | .yarn/install-state.gz 27 | .yarn/build-state.yml 28 | .eslintcache 29 | 30 | # debug 31 | npm-debug.log* 32 | yarn-debug.log* 33 | yarn-error.log* 34 | package-lock.json -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | //app 2 | const { getEthPrice } = require( "./uniswapV2SubGraph"); 3 | const { getUSDPrice } = require( "./api/cryptoCompareApi"); 4 | const { getBlocks } = require( "./api/fbBlocks"); 5 | const { getToken } = require( "./token/findToken"); 6 | const { getReceipts } = require( "./trxReceipts"); 7 | 8 | getEthPrice(true); 9 | getUSDPrice('CHI',true); 10 | 11 | getToken('0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',true); 12 | getBlocks({},true); 13 | getReceipts({transaction_hash:'0x8f7a7b99a29f5d848c39ad9d61719e4923c5d47dfd3bb6e869cdd5f406da56e2'}, true); 14 | 15 | // module.exports app; -------------------------------------------------------------------------------- /ofac-eth-list.json: -------------------------------------------------------------------------------- 1 | [ 2 | "0x7F367cC41522cE07553e823bf3be79A889DEbe1B", 3 | "0xd882cfc20f52f2599d84b8e8d58c7fb62cfe344b", 4 | "0x901bb9583b24d97e995513c6778dc6888ab6870e", 5 | "0xa7e5d5a720f06526557c513402f2e6b5fa20b00", 6 | "0x8576acc5c05d6ce88f4e49bf65bdf0c62f91353c", 7 | "0x1da5821544e25c636c1417ba96ade4cf6d2f9b5a", 8 | "0x7Db418b5D567A4e0E8c59Ad71BE1FcE48f3E6107", 9 | "0x72a5843cc08275C8171E582972Aa4fDa8C397B2A", 10 | "0x7F19720A857F834887FC9A7bC0a0fBe7Fc7f8102", 11 | "0x9f4cda013e354b8fc285bf4b9a60460cee7f7ea9", 12 | "0x2f389ce8bd8ff92de3402ffce4691d17fc4f6535", 13 | "0x19aa5fe80d33a56d56c78e82ea5e50e5d80b4dff", 14 | "0xe7aa314c77f4233c18c6cc84384a9247c0cf367b", 15 | "0x308ed4b7b49797e1a98d3818bff6fe5385410370" 16 | ] -------------------------------------------------------------------------------- /api/cryptoCompareApi.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios'); 2 | 3 | const cryptoApi = _symbol => `https://min-api.cryptocompare.com/data/price?fsym=${_symbol}&tsyms=USD`; 4 | 5 | const getUSDPrice = async (sym, debug) => { 6 | const purl = cryptoApi(sym); 7 | if(debug) console.log(purl); 8 | 9 | const config = { 10 | timeout: 30000, 11 | url: purl, 12 | method: 'get', 13 | responseType: 'json' 14 | }; 15 | const res = await axios(config); 16 | const data = res.data; 17 | 18 | if (data.USD > 0) { 19 | if(debug) console.log('usd --', data.USD); 20 | return parseFloat(data.USD).toFixed(2); 21 | } 22 | 23 | return 0; 24 | } 25 | 26 | // console.log('start --'); 27 | // getUSDPrice('CHI', true); 28 | // getUSDPrice('DAI', true); 29 | 30 | module.exports = { 31 | getUSDPrice 32 | } 33 | return; -------------------------------------------------------------------------------- /hardhat/contracts/YourContract.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.8.0 <0.9.0; 2 | //SPDX-License-Identifier: MIT 3 | 4 | // import "hardhat/console.sol"; 5 | // import "@openzeppelin/contracts/access/Ownable.sol"; 6 | // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol 7 | 8 | contract YourContract { 9 | 10 | event SetPurpose(address sender, string purpose); 11 | 12 | string public purpose = "Building Unstoppable Apps!!!"; 13 | 14 | constructor() payable { 15 | // what should we do on deploy? 16 | } 17 | 18 | function setPurpose(string memory newPurpose) public { 19 | purpose = newPurpose; 20 | // console.log(msg.sender,"set purpose to",purpose); 21 | emit SetPurpose(msg.sender, purpose); 22 | } 23 | 24 | // to support receiving ETH by default 25 | receive() external payable {} 26 | fallback() external payable {} 27 | } 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eth-scripts", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node app.js" 9 | }, 10 | "author": { 11 | "name": "harry", 12 | "url": "https://github.com/xjjda22" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/xjjda22/scripts" 17 | }, 18 | "license": "ISC", 19 | "dependencies": { 20 | "async": ">=2.6.4", 21 | "@ethersproject/abi": "^5.5.0", 22 | "@nomiclabs/hardhat-ethers": "^2.0.5", 23 | "@nomiclabs/hardhat-waffle": "^2.0.3", 24 | "abi-decoder": "^2.4.0", 25 | "axios": "^0.21.4", 26 | "dotenv": "^10.0.0", 27 | "ethers": "^5.5.1", 28 | "evm": "^0.2.0", 29 | "fs": "0.0.1-security", 30 | "hardhat": "^2.9.2", 31 | "hardhat-deploy": "^0.11.4", 32 | "tabletojson": "^2.0.7" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /token/findToken.js: -------------------------------------------------------------------------------- 1 | //findToken 2 | const DEXES = ["coingecko"]; 3 | 4 | let tokensList = []; 5 | const loadTokens = () => { 6 | DEXES.map(d => { 7 | let { tokens } = require(`./json/${d}-json.json`) 8 | tokensList.push(tokens); 9 | }) 10 | } 11 | loadTokens(); 12 | 13 | const getToken = (_address, debug) =>{ 14 | let c = { 15 | coin: "", 16 | logo: "", 17 | decimals: 18 18 | }; 19 | 20 | for (let d in tokensList) { 21 | for (let t in tokensList[d]) { 22 | let o = tokensList[d][t]; 23 | if (o.address === _address) { 24 | c.coin = o.symbol; 25 | c.logo = o.logoURI ? o.logoURI : ""; 26 | c.decimals = o.decimals ? o.decimals : 0; 27 | break; 28 | } 29 | } 30 | 31 | if (c.coin !== "") { 32 | break; 33 | } 34 | } 35 | if(debug) console.log('coin --', c); 36 | return c; 37 | } 38 | 39 | // console.log('start --'); 40 | // getToken('0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', true); 41 | 42 | module.exports = { 43 | getToken 44 | } 45 | return; 46 | -------------------------------------------------------------------------------- /util/tokensnifferScrapper.js: -------------------------------------------------------------------------------- 1 | //tokensniffer 2 | 3 | //npm install tabletojson 4 | //npm install fs 5 | 6 | const fs = require('fs'); 7 | const tabletojson = require('tabletojson').Tabletojson; 8 | 9 | const site = "https://tokensniffer.com/tokens/scam"; 10 | 11 | const readFiles = async pf => { 12 | tabletojson.convertUrl(site) 13 | .then( (tableData) => { 14 | if (!tableData) { 15 | console.error(`error fetching data from : ${tableData}`); 16 | return false; 17 | } else { 18 | console.log('writing files -- '); 19 | let tokensArr = []; 20 | tableData[0].map(t =>{ 21 | let obj = { 22 | "address": t.Symbol, 23 | "symbol": t.BitClave, 24 | "network": t.Address, 25 | "added": t.Network 26 | } 27 | tokensArr.push(obj); 28 | }) 29 | const data = { 30 | total: tokensArr.length, 31 | tokens: tokensArr 32 | } 33 | console.log('tableData',tableData); 34 | fs.writeFile(`${__dirname}/json/tokensniffer-scam-tokens.json`, JSON.stringify(data), console.error); 35 | return true; 36 | } 37 | }); 38 | } 39 | 40 | readFiles(); -------------------------------------------------------------------------------- /util/etherscanScrapper.js: -------------------------------------------------------------------------------- 1 | //etherscanScrapper 2 | 3 | //npm install tabletojson 4 | //npm install fs 5 | 6 | const fs = require('fs'); 7 | const tabletojson = require('tabletojson').Tabletojson; 8 | 9 | // const site = "https://etherscan.io/accounts/label/compound"; 10 | 11 | const readFiles = async (s, n) => { 12 | tabletojson.convertUrl(s) 13 | .then( (tableData) => { 14 | if (!tableData) { 15 | console.error(`error fetching data from : ${tableData}`); 16 | return false; 17 | } else { 18 | console.log('writing files -- '); 19 | let tokensArr = []; 20 | tableData[0].map(t =>{ 21 | let obj = { 22 | "address": t.Address, 23 | "name": t['Name Tag'] 24 | } 25 | tokensArr.push(obj); 26 | }) 27 | const data = { 28 | total: tokensArr.length, 29 | tokens: tokensArr 30 | } 31 | console.log('tableData',tableData); 32 | fs.writeFile(`${__dirname}/json/etherscan-sniffer-${n}-tokens.json`, JSON.stringify(data), console.error); 33 | return true; 34 | } 35 | }); 36 | } 37 | 38 | readFiles("https://etherscan.io/accounts/label/compound","compound"); -------------------------------------------------------------------------------- /foundry/lib/forge-std/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021 Brock Elmore 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE O THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE.R 26 | -------------------------------------------------------------------------------- /api/fbBlocks.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios'); 2 | const { inspect } = require('util'); 3 | 4 | const deepLogs = (obj) => { 5 | return inspect(obj, {depth: 5}); 6 | } 7 | 8 | const API_URL = 'https://blocks.flashbots.net/v1/blocks'; 9 | 10 | const getBlocks = async (params, debug) => { 11 | params.limit = '10'; 12 | const fburl = `${API_URL}/?${new URLSearchParams(params)}`; 13 | 14 | const config = { 15 | timeout: 30000, 16 | url: fburl, 17 | method: 'get', 18 | responseType: 'json' 19 | }; 20 | const res = await axios(config); 21 | const { blocks } = res.data; 22 | 23 | const bblocks = blocks.map(block => transformBundle(block)); 24 | if(debug) console.log('blocks --',deepLogs(bblocks)); 25 | return bblocks; 26 | } 27 | 28 | const getSubBundles = (bundle) => { 29 | return bundle.transactions.reduce((acc, curr) => { 30 | if (acc[curr.bundle_index]) { 31 | acc[curr.bundle_index].push(curr); 32 | } else { 33 | acc[curr.bundle_index] = [curr]; 34 | } 35 | return acc; 36 | }, []); 37 | } 38 | 39 | const transformBundle = (bundle) => { 40 | bundle.transactions = getSubBundles(bundle); 41 | return bundle; 42 | } 43 | 44 | // console.log('start --'); 45 | // getBlocks({}, true); 46 | 47 | module.exports = { 48 | getBlocks 49 | } 50 | return; 51 | -------------------------------------------------------------------------------- /foundry/src/test/BasicTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.0; 3 | 4 | import {Test, stdError} from "@forge-std/Test.sol"; 5 | import {console} from "../utils/Console.sol"; 6 | 7 | import {BasicToken} from "../BasicToken.sol"; 8 | 9 | 10 | contract BasicTokenTest is Test { 11 | BasicToken bt; 12 | address btAcc; 13 | address initAcc; 14 | address aliceAcc = 0x000000000000000000636F6e736F6c652e6c6f67; 15 | address bobAcc = 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045; 16 | 17 | function setUp() public { 18 | // console.log('setUp', msg.sender); 19 | // console.log('block.number', block.number); 20 | 21 | initAcc = payable(msg.sender); 22 | btAcc = deployCode("BasicToken.sol",abi.encode('BasicTokenMOCK','BTM')); 23 | bt = BasicToken(btAcc); 24 | 25 | // console.log('balance btAcc',btAcc.balance); 26 | } 27 | 28 | function testC() public { 29 | // console.log('testName', msg.sender); 30 | assertEq(bt.name(),'BasicTokenMOCK'); 31 | assertEq(bt.symbol(),'BTM'); 32 | } 33 | 34 | function testKill() public payable{ 35 | startHoax(initAcc); 36 | bt.mint(initAcc, 1e77); 37 | assertTrue(true); 38 | // assertEq(bt.balanceOf(initAcc),1000); 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /token/fetchPools.js: -------------------------------------------------------------------------------- 1 | //npm install fs 2 | //npm install axios 3 | 4 | //ex - node fetchPools.js 5 | 6 | const path = require('path'); 7 | require('dotenv').config({path:path.resolve('../', '.env')}); 8 | 9 | const fs = require('fs'); 10 | const axios = require('axios'); 11 | 12 | const { DEFIPULSE_APIKEY } = process.env; 13 | 14 | const poolNames = [ 15 | "uniswap-v2", 16 | "sushiswap", 17 | "mooniswap", 18 | "curve", 19 | "balancer" 20 | ]; 21 | const poolApi = pf => `https://data-api.defipulse.com/api/v1/blocklytics/pools/v1/exchanges?platform=${pf}&orderBy=usdLiquidity&direction=desc&api-key=${DEFIPULSE_APIKEY}`; 22 | 23 | const readFiles = async pf => { 24 | const poolUrl = poolApi(pf); 25 | console.log(poolUrl); 26 | 27 | const config = { 28 | timeout: 30000, 29 | url: poolUrl, 30 | method: 'get', 31 | responseType: 'json' 32 | }; 33 | 34 | const { data } = await axios(config); 35 | 36 | if (!data) { 37 | console.error(`error fetching data from ${this.name}: ${error}`); 38 | return false; 39 | } else { 40 | console.log('writing files -- '); 41 | fs.writeFile(`${__dirname}/json/${pf}-pools.json`, JSON.stringify(data), console.error); 42 | return true; 43 | } 44 | } 45 | 46 | // readFiles('uniswap-v2'); 47 | // readFiles('sushiswap'); 48 | // readFiles('mooniswap'); 49 | // readFiles('curve'); 50 | // readFiles('balancer'); -------------------------------------------------------------------------------- /ABIEvents.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | //erc20 3 | { "text_signature": "event Transfer(address indexed from, address indexed to, uint256 value)", }, 4 | { "text_signature": "event Approval(address indexed owner, address indexed spender, uint256 value)", }, 5 | //WETH 6 | { "text_signature": "event Deposit(address indexed dst, uint wad)", }, 7 | { "text_signature": "event Withdrawal(address indexed src, uint wad)", }, 8 | //IUniswapExchange 9 | { "text_signature": "event TokenPurchase(address indexed buyer, uint256 indexed eth_sold, uint256 indexed tokens_bought)" }, 10 | { "text_signature": "event EthPurchase(address indexed buyer, uint256 indexed tokens_sold, uint256 indexed eth_bought)" }, 11 | { "text_signature": "event AddLiquidity(address indexed provider, uint256 indexed eth_amount, uint256 indexed token_amount)" }, 12 | { "text_signature": "event RemoveLiquidity(address indexed provider, uint256 indexed eth_amount, uint256 indexed token_amount)" }, 13 | //IUniswapV2Pair 14 | { "text_signature": "event Mint(address indexed sender, uint amount0, uint amount1)" }, 15 | { "text_signature": "event Burn(address indexed sender, uint amount0, uint amount1, address indexed to)" }, 16 | { "text_signature": "event Swap(address indexed sender, uint amount0, uint amount1, uint amount0Out, uint amount1Out, address indexed to)" }, 17 | { "text_signature": "event Sync(uint112 reserve0, uint112 reserve1)" } 18 | ] -------------------------------------------------------------------------------- /foundry/src/BasicToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.0; 3 | 4 | contract BasicToken { 5 | 6 | mapping(address => uint256) private _balances; 7 | 8 | uint256 private _totalSupply; 9 | string private _name; 10 | string private _symbol; 11 | 12 | 13 | event Transfer(address indexed from, address indexed to, uint256 value); 14 | 15 | constructor(string memory name_, string memory symbol_) { 16 | _name = name_; 17 | _symbol = symbol_; 18 | } 19 | 20 | function name() public view virtual returns (string memory) { 21 | return _name; 22 | } 23 | function symbol() public view virtual returns (string memory) { 24 | return _symbol; 25 | } 26 | function totalSupply() public view virtual returns (uint256) { 27 | return _totalSupply; 28 | } 29 | function balanceOf(address account) public view virtual returns (uint256) { 30 | return _balances[account]; 31 | } 32 | 33 | function mint(address account, uint256 amount) public virtual { 34 | require(account != address(0), "ERC20: mint to the zero address"); 35 | 36 | _totalSupply += amount; 37 | _balances[account] += amount; 38 | emit Transfer(address(0), account, amount); 39 | } 40 | 41 | // function kill(address payable target) external { 42 | // selfdestruct(target); 43 | // } 44 | } 45 | 46 | -------------------------------------------------------------------------------- /trxReceipts.js: -------------------------------------------------------------------------------- 1 | //trxReceipts 2 | require('dotenv').config(); 3 | const axios = require('axios'); 4 | const { inspect } = require('util'); 5 | const { getAllLogs } = require('./ABILogs'); 6 | 7 | const deepLogs = (obj) => { 8 | return inspect(obj, {depth: 5}); 9 | } 10 | 11 | const { INFURA_APIKEY } = process.env; 12 | 13 | const getReceipts = async (transaction, debug) => { 14 | const rpc = { 15 | "jsonrpc": "2.0", 16 | "method": "eth_getTransactionReceipt", 17 | "params": [], 18 | "id": 1 19 | }; 20 | 21 | const { transaction_hash } = transaction; 22 | rpc.params = [transaction_hash]; 23 | 24 | try { 25 | const infuraUrl = `https://mainnet.infura.io/v3/${INFURA_APIKEY}`; 26 | const config = { 27 | timeout: 30000, 28 | url: infuraUrl, 29 | method: 'post', 30 | headers: { 31 | "Accept": "application/json", 32 | 'Content-Type': 'application/json' 33 | }, 34 | data: rpc, 35 | responseType: 'json' 36 | }; 37 | const res = await axios(config); 38 | const { result : { logs } } = res.data; 39 | const uplogs = await getAllLogs(logs); 40 | 41 | if(debug) console.log('uplogs --',deepLogs(uplogs)); 42 | 43 | return uplogs; 44 | } catch(e) { 45 | console.log(e); 46 | } 47 | 48 | return []; 49 | } 50 | 51 | // console.log('start --'); 52 | // getReceipts({transaction_hash:'0x8f7a7b99a29f5d848c39ad9d61719e4923c5d47dfd3bb6e869cdd5f406da56e2'}, true); 53 | // getReceipts({transaction_hash:'0x92b7bc6072347f765f1d788f607d7e0beafc7d1cf247b8b2020053c02886227b'}, true); 54 | 55 | module.exports = { 56 | getReceipts 57 | } 58 | return; 59 | -------------------------------------------------------------------------------- /cryptoPunksTxs.js: -------------------------------------------------------------------------------- 1 | // cryptoPunksTxs 2 | // curl --data '{"method":"txpool_inspect","id":1,"jsonrpc":"2.0"}' -H "Content-Type: application/json" -X POST https://api.archivenode.io/ 3 | require('dotenv').config(); 4 | const { providers, utils } = require("ethers"); 5 | 6 | const { INFURA_APIKEY, ARCHIVENODE_APIKEY } = process.env; 7 | const CRYPTOPUNKS_CONT = '0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb'; 8 | const addr = CRYPTOPUNKS_CONT.toLowerCase(); 9 | 10 | const ETHEREUM_RPC_URL = `https://mainnet.infura.io/v3/${INFURA_APIKEY}`; 11 | 12 | const provider = new providers.StaticJsonRpcProvider(ETHEREUM_RPC_URL); 13 | // const provider = new providers.JsonRpcProvider(ETHEREUM_RPC_URL); 14 | // const provider = new providers.getDefaultProvider(ETHEREUM_RPC_URL); 15 | 16 | console.log('start --'); 17 | console.log('ETHEREUM_RPC_URL',ETHEREUM_RPC_URL); 18 | provider.on("block", async (blockNumber) => { 19 | console.log('blockNumber',blockNumber); 20 | }); 21 | provider.on("pending", async (tx) => { 22 | console.log('listen --'); 23 | console.log('tx:',tx ); 24 | 25 | setTimeout(async () => { 26 | try { 27 | let tx = await provider.getTransaction(txHash); 28 | if (tx && tx.to && tx.to.toLowerCase() === addr) { 29 | console.log('tx hash: ',txHash ); 30 | console.log('tx confirmation index: ',tx.transactionIndex );// 0 when transaction is pending 31 | console.log('tx from: ',tx.from ); 32 | console.log('tx amount (in ether): ',utils.fromWei(tx.value, 'ether')); 33 | console.log('tx receiving date/time: ',new Date()); 34 | } 35 | } catch (err) { 36 | console.error(err); 37 | } 38 | }, 15 * 1000); // running at 15 seconds 39 | }); 40 | -------------------------------------------------------------------------------- /util/4byteEventsApi.js: -------------------------------------------------------------------------------- 1 | //4byteEventsApi 2 | //npm install fs 3 | //npm install axios 4 | 5 | //ex - node fetchTokens.js 6 | 7 | const fs = require('fs'); 8 | const axios = require('axios'); 9 | 10 | const siteUrl = "https://www.4byte.directory/api/v1/event-signatures/?format=json"; 11 | 12 | const validURL = (str) => { 13 | var pattern = new RegExp('^(https?:\\/\\/)?'+ // protocol 14 | '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name 15 | '((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address 16 | '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path 17 | '(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string 18 | '(\\#[-a-z\\d_]*)?$','i'); // fragment locator 19 | return !!pattern.test(str); 20 | } 21 | 22 | const readFiles = async (_eventsArr, _n) => { 23 | const sturl = _n == 0 ? siteUrl : _n; 24 | 25 | const config = { 26 | timeout: 30000, 27 | url: sturl, 28 | method: 'get', 29 | responseType: 'json' 30 | }; 31 | 32 | let { data : { results , next } } = await axios(config); 33 | console.log('continue', next); 34 | 35 | if(results.length > 0) { 36 | _eventsArr = _eventsArr.concat(results); 37 | } 38 | 39 | if(validURL(next)){ 40 | readFiles(_eventsArr, next); 41 | return true; 42 | } 43 | 44 | if (!_eventsArr) { 45 | console.error(`error fetching results from ${this.name}: ${error}`); 46 | return false; 47 | } else { 48 | console.log('writing files -- '); 49 | const resultsObj = { 50 | "results":_eventsArr, 51 | "count":_eventsArr.length, 52 | } 53 | console.log('resultsObj',resultsObj); 54 | fs.writeFile(`${__dirname}/json/4byte-events.json`, global.JSON.stringify(resultsObj), console.error); 55 | return true; 56 | } 57 | } 58 | 59 | let eventsArr = []; 60 | let n = 0; 61 | readFiles(eventsArr, n); -------------------------------------------------------------------------------- /mpoolPendingTxs.js: -------------------------------------------------------------------------------- 1 | // mpoolPendingTxs 2 | // curl --data '{"method":"txpool_inspect","id":1,"jsonrpc":"2.0"}' -H "Content-Type: application/json" -X POST https://api.archivenode.io/ 3 | require('dotenv').config(); 4 | const { providers, utils } = require("ethers"); 5 | 6 | const { INFURA_APIKEY, ARCHIVENODE_APIKEY } = process.env; 7 | const UNIV2_ROUTER = '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D'; 8 | const addr = UNIV2_ROUTER.toLowerCase(); 9 | 10 | // const ETHEREUM_RPC_URL = `https://mainnet.infura.io/v3/${INFURA_APIKEY}`; 11 | const ETHEREUM_RPC_URL = `https://api.archivenode.io/${ARCHIVENODE_APIKEY}`; 12 | 13 | const provider = new providers.StaticJsonRpcProvider(ETHEREUM_RPC_URL); 14 | // const provider = new providers.JsonRpcProvider(ETHEREUM_RPC_URL); 15 | // const provider = new providers.getDefaultProvider(ETHEREUM_RPC_URL); 16 | 17 | console.log('start --'); 18 | console.log('ETHEREUM_RPC_URL',ETHEREUM_RPC_URL); 19 | provider.on("block", async (blockNumber) => { 20 | console.log('blockNumber',blockNumber); 21 | }); 22 | provider.on("pending", async (tx) => { 23 | console.log('listen --'); 24 | console.log('tx:',tx ); 25 | 26 | // setTimeout(async () => { 27 | // try { 28 | // let tx = await provider.getTransaction(txHash); 29 | // if (tx && tx.from && tx.from.toLowerCase() === addr) { 30 | // console.log('tx hash: ',txHash ); 31 | // console.log('tx confirmation index: ',tx.transactionIndex );// 0 when transaction is pending 32 | // console.log('tx from: ',tx.from ); 33 | // // console.log('tx amount (in ether): ',utils.fromWei(tx.value, 'ether')); 34 | // console.log('tx receiving date/time: ',new Date()); 35 | // } 36 | // } catch (err) { 37 | // console.error(err); 38 | // } 39 | // }, 15 * 1000); // running at 15 seconds 40 | }); 41 | 42 | -------------------------------------------------------------------------------- /token/fetchTokens.js: -------------------------------------------------------------------------------- 1 | //npm install fs 2 | //npm install axios 3 | 4 | //ex - node fetchTokens.js 5 | 6 | const fs = require('fs'); 7 | const axios = require('axios'); 8 | 9 | const dexUrl = { 10 | 'coingecko': "https://tokens.coingecko.com/uniswap/all.json", 11 | 'coingecko-coins': "https://api.coingecko.com/api/v3/coins/list", 12 | '1inch': "https://api.1inch.exchange/v3.0/1/tokens", 13 | '0x': "https://api.0x.org/swap/v1/tokens", 14 | 'kyber': "https://api.kyber.network/currencies", 15 | }; 16 | 17 | const tokensBySymbol = {} 18 | 19 | const readFiles = async dex => { 20 | const tokensUrl = dexUrl[dex]; 21 | 22 | const config = { 23 | timeout: 30000, 24 | url: tokensUrl, 25 | method: 'get', 26 | responseType: 'json' 27 | }; 28 | 29 | let { data } = await axios(config); 30 | 31 | if (!data) { 32 | console.error(`error fetching data from ${this.name}: ${error}`); 33 | return false; 34 | } else { 35 | console.log('writing files -- '); 36 | if(dex == 'coingecko') { 37 | let { tokens } = data; 38 | data.total = tokens.length; 39 | } else if(dex == 'coingecko-coins'){ 40 | 41 | } else if(dex == '1inch'){ 42 | let { tokens } = data; 43 | data.total = Object.keys(tokens).length; 44 | } else if(dex == '0x'){ 45 | let { records } = data; 46 | data.total = records.length; 47 | } else if(dex == 'kyber'){ 48 | data.total = data.data.length; 49 | } 50 | fs.writeFile(`${__dirname}/json/${dex}-json.json`, global.JSON.stringify(data), console.error); 51 | 52 | // if(dex == 'coingecko'){ 53 | // tokens.forEach(token => { 54 | // tokensBySymbol[token.symbol] = token; 55 | // }) 56 | // fs.writeFile(`${__dirname}/json/${dex}-tokens.json`, global.JSON.stringify(tokensBySymbol), console.error); 57 | // } else if(dex == '1inch'){ 58 | 59 | // } 60 | return true; 61 | } 62 | } 63 | 64 | // readFiles('coingecko'); 65 | // readFiles('1inch'); 66 | // readFiles('0x'); 67 | // readFiles('kyber'); 68 | // readFiles('coingecko-coins'); 69 | -------------------------------------------------------------------------------- /hardhat/hardhat.config.js: -------------------------------------------------------------------------------- 1 | // hardhat.config.js 2 | const path = require('path'); 3 | require('dotenv').config({path:path.resolve('../', '.env')}); 4 | const fs = require("fs"); 5 | require("@nomiclabs/hardhat-waffle"); 6 | 7 | const { INFURA_APIKEY } = process.env; 8 | 9 | const defaultNetwork = "mainnet"; 10 | const mainnetGwei = 21; 11 | 12 | const mnemonic = () => { 13 | try { 14 | return fs.readFileSync("./mnemonic.txt").toString().trim(); 15 | } catch (e) { 16 | if (defaultNetwork !== "localhost") { 17 | console.log( 18 | "☢️ WARNING: No mnemonic file created for a deploy account. Try `yarn run generate` and then `yarn run account`." 19 | ); 20 | } 21 | } 22 | return ""; 23 | } 24 | module.exports = { 25 | defaultNetwork, 26 | networks: { 27 | localhost: { 28 | url: "http://localhost:8545", 29 | }, 30 | mainnet: { 31 | url: "https://mainnet.infura.io/v3/"+INFURA_APIKEY, // <---- YOUR INFURA ID! (or it won't work) 32 | // url: "https://speedy-nodes-nyc.moralis.io/XXXXXXXXXXXXXXXXXXXXXXXXX/eth/mainnet", // <---- YOUR MORALIS ID! (not limited to infura) 33 | gasPrice: mainnetGwei * 1000000000, 34 | // accounts: { 35 | // mnemonic: mnemonic(), 36 | // }, 37 | }, 38 | xdai: { 39 | url: "https://rpc.xdaichain.com/", 40 | gasPrice: 1000000000, 41 | // accounts: { 42 | // mnemonic: mnemonic(), 43 | // }, 44 | }, 45 | }, 46 | solidity: { 47 | compilers: [ 48 | { 49 | version: "0.8.4", 50 | settings: { 51 | optimizer: { 52 | enabled: true, 53 | runs: 200, 54 | }, 55 | }, 56 | }, 57 | { 58 | version: "0.6.7", 59 | settings: { 60 | optimizer: { 61 | enabled: true, 62 | runs: 200, 63 | }, 64 | }, 65 | }, 66 | ], 67 | }, 68 | namedAccounts: { 69 | deployer: { 70 | default: 0, // here this will by default take the first account as deployer 71 | }, 72 | } 73 | }; -------------------------------------------------------------------------------- /gasPrices.js: -------------------------------------------------------------------------------- 1 | // gasPrices 2 | require('dotenv').config(); 3 | const axios = require('axios'); 4 | const { inspect } = require('util'); 5 | 6 | const deepLogs = (obj) => { 7 | return inspect(obj, {depth: 5}); 8 | } 9 | 10 | const { ETHERSCAN_APIKEY, BLOCKNATIVE_APIKEY } = process.env; 11 | 12 | const gasPrices = async (api, debug) => { 13 | 14 | const api_url = `${api}`; 15 | 16 | const config = { 17 | timeout: 30000, 18 | url: api_url, 19 | method: 'get', 20 | responseType: 'json' 21 | }; 22 | const res = await axios(config); 23 | const data = res.data; 24 | if(debug) console.log('data -- ',api, deepLogs(data) ); 25 | return data; 26 | } 27 | 28 | const gasPricesWithAuth = async (api, token, debug) => { 29 | 30 | const api_url = `${api}`; 31 | 32 | let config = { 33 | timeout: 30000, 34 | url: api_url, 35 | method: 'get', 36 | responseType: 'json', 37 | headers : { 38 | Authorization : `${token}` 39 | } 40 | }; 41 | const res = await axios(config); 42 | const data = res.data; 43 | if(debug) console.log('data -- ',api, deepLogs(data) ); 44 | return data; 45 | } 46 | 47 | // console.log('start --'); 48 | // gasPrices("https://ethgasstation.info/json/ethgasAPI.json", true); 49 | // gasPrices("https://www.gasnow.org/api/v3/gas/price", true); 50 | // gasPrices("https://safe-relay.gnosis.io/api/v1/gas-station/", true); 51 | // gasPrices("https://api.txprice.com/", true); 52 | // gasPrices("https://api.metaswap.codefi.network/gasPrices", true); 53 | // gasPrices("https://www.etherchain.org/api/gasnow", true); 54 | // gasPrices(`https://api.etherscan.io/api?module=gastracker&action=gasoracle&apikey=${ETHERSCAN_APIKEY}`, true); 55 | // gasPrices(`https://api.gasprice.io/v1/estimates`, true); 56 | // gasPrices(`https://api.archerdao.io/v1/gas`, true); 57 | gasPrices(`https://ethereum-api.xyz/gas-prices`, true); 58 | 59 | //blocknative 60 | // gasPricesWithAuth(`https://api.blocknative.com/gasprices/blockprices`, BLOCKNATIVE_APIKEY, true); 61 | 62 | //GasNow 63 | //MyCrypto 64 | 65 | module.exports = { 66 | gasPrices 67 | } 68 | return; 69 | -------------------------------------------------------------------------------- /ABILogs.js: -------------------------------------------------------------------------------- 1 | //ABILogs 2 | //npm install abi-decoder 3 | //npm install @ethersproject/abi 4 | 5 | const { addABI, decodeLogs } = require("abi-decoder"); 6 | const { Interface } = require("@ethersproject/abi"); 7 | 8 | const { getToken } = require("./token/findToken"); 9 | const { getEthPrice, getPairAddress } = require("./uniswapV2SubGraph"); 10 | const { getUSDPrice } = require("./api/cryptoCompareApi"); 11 | 12 | const eventsJson = require("./ABIEvents"); 13 | 14 | const addEvents = async () => { 15 | eventsJson.map(async e => { 16 | let { text_signature } = e; 17 | try { 18 | let i = new Interface([text_signature]); 19 | await addABI(i.fragments); 20 | } catch (e) { 21 | console.log(e); 22 | } 23 | }); 24 | }; 25 | 26 | addEvents(); 27 | 28 | const getAllLogs = async (_logs) => { 29 | const ethPrice = await getEthPrice(); 30 | return await Promise.all(decodeLogs(_logs).map(async log => { 31 | let { coin, logo, decimals } = getToken(log.address); 32 | if(coin == "") { 33 | let pair = await getPairAddress(log.address); 34 | coin = pair.coin; 35 | } 36 | let ethValue = 0; 37 | let usdValue = 0; 38 | let value; 39 | 40 | if((log.name == "Transfer" || log.name == "Swap") && coin !== 'WETH' && coin !== ""){ 41 | try { 42 | usdValue = await getUSDPrice(coin); 43 | } catch (e) { 44 | console.log(e); 45 | } 46 | } 47 | 48 | log.events.map(async e => { 49 | if ((log.name == "Transfer" || log.name == "Swap") && e.type.match("uint")) { 50 | value = parseFloat(e.value / 10 ** decimals).toFixed(2); 51 | if (coin === 'WETH') { 52 | ethValue = parseFloat(value * ethPrice).toFixed(2); 53 | } else if(coin !== "") { 54 | if(usdValue > 0) ethValue = parseFloat(value * usdValue).toFixed(2); 55 | } 56 | } 57 | }); 58 | 59 | log.coin = { 60 | address: log.address, 61 | name: coin, 62 | event: log.name, 63 | logo, 64 | decimals, 65 | value, 66 | ethValue 67 | }; 68 | 69 | return log; 70 | })); 71 | } 72 | 73 | module.exports = { 74 | getAllLogs 75 | } 76 | -------------------------------------------------------------------------------- /uniswapV2SubGraph.js: -------------------------------------------------------------------------------- 1 | //uniswapV2SubGraph 2 | const axios = require('axios'); 3 | const { inspect } = require('util'); 4 | 5 | const deepLogs = (obj) => { 6 | return inspect(obj, {depth: 5}); 7 | } 8 | 9 | // const USDC = { 10 | // "chainId": 1, 11 | // "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", 12 | // "name": "USD Coin", 13 | // "symbol": "USDC", 14 | // "decimals": 6, 15 | // "logoURI": "https://assets.coingecko.com/coins/images/6319/thumb/USD_Coin_icon.png?1547042389" 16 | // }; 17 | 18 | const urlArr = [ 19 | "https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2", 20 | "https://api.thegraph.com/subgraphs/name/sushiswap/exchange", 21 | ]; 22 | const ethQL = `{ 23 | bundles (first:1) { 24 | ethPrice 25 | } 26 | }`; 27 | const pairQL = (_address) =>`{ 28 | pair(id: "${_address}") { 29 | token0 { 30 | symbol 31 | } 32 | token1 { 33 | symbol 34 | } 35 | } 36 | }`; 37 | 38 | const getEthPrice = async (debug) => { 39 | const config = { 40 | timeout: 30000, 41 | url: urlArr[0], 42 | method: 'post', 43 | headers: { 44 | // 'Accept': 'api_version=2', 45 | // 'Content-Type': 'application/graphql', 46 | 'Content-Type': 'application/json' 47 | }, 48 | // body: JSON.stringify({ query : ethQL }), 49 | data: { query : ethQL }, 50 | responseType: 'json' 51 | }; 52 | const res = await axios(config); 53 | const { data } = res.data; 54 | 55 | if (data.bundles.length > 0) { 56 | if(debug) console.log('ethprice --',data.bundles[0].ethPrice); 57 | return parseFloat(data.bundles[0].ethPrice).toFixed(6); 58 | } 59 | 60 | return 0; 61 | } 62 | 63 | const getPairAddress = async (_address, debug) =>{ 64 | let c = { 65 | coin: "", 66 | logo: "", 67 | decimals: 18 68 | }; 69 | const gQL = pairQL(_address); 70 | 71 | for (let i in urlArr) { 72 | const config = { 73 | timeout: 30000, 74 | url: urlArr[i], 75 | method: 'post', 76 | headers: { 77 | // 'Accept': 'api_version=2', 78 | // 'Content-Type': 'application/graphql', 79 | 'Content-Type': 'application/json' 80 | }, 81 | // body: JSON.stringify({ query : gQL }), 82 | data: { query : gQL }, 83 | responseType: 'json' 84 | }; 85 | const res = await axios(config); 86 | const { data: { pair } } = res.data; 87 | 88 | if(pair != null){ 89 | c.coin = `${pair.token0.symbol}-${pair.token1.symbol}` 90 | break; 91 | } 92 | } 93 | if(debug) console.log('coin --',c); 94 | return c; 95 | } 96 | 97 | // console.log('start --'); 98 | // getEthPrice(true); 99 | // getPairAddress('0x4214290310264a27b0ba8cff02b4c592d0234aa1',true); 100 | 101 | module.exports = { 102 | getEthPrice, 103 | getPairAddress 104 | } 105 | return; 106 | -------------------------------------------------------------------------------- /api/coingeckoApi.js: -------------------------------------------------------------------------------- 1 | //npm install fs 2 | //npm install axios 3 | 4 | //ex - node oneInchQuote.js 5 | 6 | const axios = require('axios'); 7 | const { inspect } = require('util'); 8 | 9 | const deepLogs = (obj) => { 10 | return inspect(obj, {depth: 5}); 11 | } 12 | 13 | //https://api.coingecko.com/api/v3/exchanges/list 14 | let protocols = [ 15 | "uniswap", 16 | "uniswap_v1", 17 | "uniswap_v2", 18 | "sushiswap", 19 | "aave", 20 | "curve", 21 | "synthetix", 22 | "compound", 23 | "dydx", 24 | "kyber_network", 25 | "bancor", 26 | "1inch", 27 | "balancer", 28 | "balancer_v1", 29 | "bamboo_relay", 30 | "zero_ex", 31 | ]; 32 | 33 | //https://api.coingecko.com/api/v3/coins/list 34 | let coinsList = require('./json/coingecko-coins-json.json'); 35 | // let tokensArr = []; 36 | // coinsList.map( c => { 37 | // if(c.name.toLowerCase().includes('weth') || 38 | // c.name.toLowerCase().includes('usd') || 39 | // c.name.toLowerCase().includes('tether') || 40 | // c.name.toLowerCase().includes('dai')){ 41 | // tokensArr.push(c); 42 | // } 43 | // }) 44 | // console.table(tokensArr); 45 | let tokens = [ 46 | "usd-coin", 47 | "tether", 48 | "weth", 49 | "dai", 50 | ]; 51 | 52 | 53 | const exchangesApi = (plat) => `https://api.coingecko.com/api/v3/exchanges/${plat}`; 54 | const coinTickersApi = (token) => `https://api.coingecko.com/api/v3/coins/${token}/tickers?exchange_ids=${protocols.join(',')}`; 55 | let config = { 56 | timeout: 30000, 57 | url: '', 58 | method: 'get', 59 | responseType: 'json' 60 | }; 61 | 62 | const getQuote = async (token, debug) => { 63 | 64 | let platres,platdata; 65 | 66 | const platurl = coinTickersApi(token); 67 | config.url = platurl; 68 | // if(debug) console.log(platurl); 69 | 70 | try{ 71 | platres = await axios(config); 72 | platdata = platres.data; 73 | } catch (e){ 74 | console.log(e.response.data); 75 | return; 76 | } 77 | 78 | if (!platdata) { 79 | console.error(`error fetching data from ${this.name}: ${platdata}`); 80 | return false; 81 | } else { 82 | 83 | // if(debug) console.log('platdata -- ',deepLogs(platdata)); 84 | if(debug) { 85 | platdata.tickers.map(t => { 86 | let {base, target, coin_id, volume, last, market : { name : marketName } } = t ; 87 | let obj = { 88 | coin:coin_id, 89 | pair: `${base}-${target}`, 90 | last, 91 | volume, 92 | marketName 93 | } 94 | allTickers.push(obj); 95 | }) 96 | console.table(allTickers); 97 | } 98 | return true; 99 | } 100 | } 101 | 102 | let allTickers = []; 103 | 104 | console.log('start --'); 105 | // getQuote('usd-coin', true); 106 | // getQuote('weth', true); 107 | // getQuote('dai', true); 108 | // getQuote('tether', true); 109 | 110 | module.exports = { 111 | getQuote 112 | } 113 | return; 114 | 115 | -------------------------------------------------------------------------------- /api/kyberApi.js: -------------------------------------------------------------------------------- 1 | //npm install fs 2 | //npm install axios 3 | 4 | //ex - node oneInchQuote.js 5 | 6 | const axios = require('axios'); 7 | const { inspect } = require('util'); 8 | 9 | const deepLogs = (obj) => { 10 | return inspect(obj, {depth: 5}); 11 | } 12 | 13 | const protocols = [ 14 | "KYBER", 15 | "UNISWAP_V2", 16 | ]; 17 | 18 | const buyApi = (from, amt) => `https://api.kyber.network/buy_rate?id=${from}&qty=${amt}`; 19 | const sellApi = (from, amt) => `https://api.kyber.network/sell_rate?id=${from}&qty=${amt}`; 20 | 21 | let config = { 22 | timeout: 30000, 23 | url: '', 24 | method: 'get', 25 | responseType: 'json' 26 | }; 27 | 28 | const getQuote = async (from, amt, dec, debug) => { 29 | 30 | let buyres,buydata,retbuyamt; 31 | let sellres,selldata,retsellamt; 32 | 33 | const buyurl = buyApi(from, amt); 34 | config.url = buyurl; 35 | // if(debug) console.log(buyurl); 36 | 37 | try{ 38 | buyres = await axios(config); 39 | buydata = buyres.data; 40 | if(!buydata.error){ 41 | retbuyamt = buydata.data[0].dst_qty[0]; 42 | } 43 | } catch (e){ 44 | console.log(e.response.data); 45 | return; 46 | } 47 | 48 | const sellurl = sellApi(from, amt); 49 | config.url = sellurl; 50 | // if(debug) console.log(sellurl); 51 | 52 | try{ 53 | sellres = await axios(config); 54 | selldata = sellres.data; 55 | if(!selldata.error){ 56 | retsellamt = selldata.data[0].dst_qty[0]; 57 | } 58 | } catch (e){ 59 | console.log(e.response.data); 60 | } 61 | 62 | if (!buydata || !selldata) { 63 | console.error(`error fetching data from ${this.name}: ${buydata}`); 64 | console.error(`error fetching data from ${this.name}: ${selldata}`); 65 | return false; 66 | } else { 67 | 68 | // if(debug) console.log('buydata -- ',deepLogs(buydata)); 69 | // if(debug) console.log('selldata -- ',deepLogs(selldata)); 70 | if(debug) { 71 | let obj = { 72 | 'buy-amt': retbuyamt, 73 | 'sell-amt': retsellamt 74 | } 75 | allTrades.push(obj); 76 | } 77 | 78 | return true; 79 | } 80 | } 81 | 82 | let _dec = '000000000000000000'; 83 | let _e = 1000000000000000000; 84 | let allTrades = []; 85 | 86 | const weth_add = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"; 87 | const usdt_add = "0xdac17f958d2ee523a2206206994597c13d831ec7"; 88 | const usdc_add = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"; 89 | 90 | const seth_add = "0x57ab1ec28d129707052df4df418d58a2d46d5f51"; 91 | 92 | let _amt = 1, _inc = 5; 93 | 94 | const runQuotes = async (debug) => { 95 | 96 | for(let _i=0;_i<5;_i++){ 97 | await getQuote(weth_add, _amt, _dec, true); 98 | await getQuote(usdc_add, _amt, _dec, true); 99 | _amt = _amt+_inc; 100 | } 101 | if(debug) console.table(allTrades); 102 | } 103 | 104 | console.log('start --'); 105 | runQuotes(true); 106 | // getQuote(weth_add, _amt, _dec, true); 107 | // getQuote(usdc_add, _amt, _dec, true); 108 | 109 | module.exports = { 110 | getQuote 111 | } 112 | return; 113 | -------------------------------------------------------------------------------- /foundry/lib/forge-std/src/test/StdError.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Unlicense 2 | pragma solidity 0.8.10; 3 | 4 | import "../Test.sol"; 5 | 6 | contract StdErrorsTest is Test { 7 | ErrorsTest test; 8 | 9 | function setUp() public { 10 | test = new ErrorsTest(); 11 | } 12 | 13 | function testExpectAssertion() public { 14 | vm.expectRevert(stdError.assertionError); 15 | test.assertionError(); 16 | } 17 | 18 | function testExpectArithmetic() public { 19 | vm.expectRevert(stdError.arithmeticError); 20 | test.arithmeticError(10); 21 | } 22 | 23 | function testExpectDiv() public { 24 | vm.expectRevert(stdError.divisionError); 25 | test.divError(0); 26 | } 27 | 28 | function testExpectMod() public { 29 | vm.expectRevert(stdError.divisionError); 30 | test.modError(0); 31 | } 32 | 33 | function testExpectEnum() public { 34 | vm.expectRevert(stdError.enumConversionError); 35 | test.enumConversion(1); 36 | } 37 | 38 | function testExpectEncodeStg() public { 39 | vm.expectRevert(stdError.encodeStorageError); 40 | test.encodeStgError(); 41 | } 42 | 43 | function testExpectPop() public { 44 | vm.expectRevert(stdError.popError); 45 | test.pop(); 46 | } 47 | 48 | function testExpectOOB() public { 49 | vm.expectRevert(stdError.indexOOBError); 50 | test.indexOOBError(1); 51 | } 52 | 53 | function testExpectMem() public { 54 | vm.expectRevert(stdError.memOverflowError); 55 | test.mem(); 56 | } 57 | 58 | function testExpectIntern() public { 59 | vm.expectRevert(stdError.zeroVarError); 60 | test.intern(); 61 | } 62 | 63 | function testExpectLowLvl() public { 64 | vm.expectRevert(stdError.lowLevelError); 65 | test.someArr(0); 66 | } 67 | } 68 | 69 | contract ErrorsTest { 70 | enum T { 71 | T1 72 | } 73 | 74 | uint256[] public someArr; 75 | bytes someBytes; 76 | 77 | function assertionError() public pure { 78 | assert(false); 79 | } 80 | 81 | function arithmeticError(uint256 a) public pure { 82 | a -= 100; 83 | } 84 | 85 | function divError(uint256 a) public pure { 86 | 100 / a; 87 | } 88 | 89 | function modError(uint256 a) public pure { 90 | 100 % a; 91 | } 92 | 93 | function enumConversion(uint256 a) public pure { 94 | T(a); 95 | } 96 | 97 | function encodeStgError() public { 98 | /// @solidity memory-safe-assembly 99 | assembly { 100 | sstore(someBytes.slot, 1) 101 | } 102 | keccak256(someBytes); 103 | } 104 | 105 | function pop() public { 106 | someArr.pop(); 107 | } 108 | 109 | function indexOOBError(uint256 a) public pure { 110 | uint256[] memory t = new uint256[](0); 111 | t[a]; 112 | } 113 | 114 | function mem() public pure { 115 | uint256 l = 2**256 / 32; 116 | new uint256[](l); 117 | } 118 | 119 | function intern() public returns (uint256) { 120 | function(uint256) internal returns (uint256) x; 121 | x(2); 122 | return 7; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # scripts 2 | 3 | ``` 4 | $ npm install 5 | 6 | ``` 7 | 8 | # 🛠 APIs 9 | - [coingecko](https://api.coingecko.com) 10 | - [cryptocompare](https://min-api.cryptocompare.com/) 11 | - [kyber](https://api.kyber.network) 12 | - [1inch](https://api.1inch.exchange) 13 | - [flashbots](https://blocks.flashbots.net) 14 | 15 | # ⛽🔥 gas prices api - gasPrices.js 16 | - [etherscan](https://api.etherscan.io/api) 17 | - [ethgasstation](https://ethgasstation.info) 18 | - [gasnow](https://www.gasnow.org/api/v3/gas/price) 19 | - [gnosis](https://safe-relay.gnosis.io/api/v1/gas-station/) 20 | - [txprice](https://api.txprice.com/) 21 | - [metaswap](https://api.metaswap.codefi.network/gasPrices) 22 | - [etherchain](https://www.etherchain.org/api/gasnow) 23 | - [gasprice.io](https://api.gasprice.io) 24 | - [archerdao](https://api.archerdao.io/v1/gas) 25 | - [WalletConnect](https://ethereum-api.xyz/gas-prices) 26 | - [blocknative](https://api.blocknative.com/gasprices/blockprices) 27 | 28 | # 🔗 chainlink feeds - chainlinkPrices.js (https://data.chain.link/) 29 | - ETH/USD (https://etherscan.io/address/0x5f4ec3df9cbd43714fe2740f5e3616155c5b8419) 30 | - BTC/USD (https://etherscan.io/address/0xf4030086522a5beea4988f8ca5b36dbc97bee88c) 31 | - BCH/USD (https://etherscan.io/address/0x9f0f69428f923d6c95b781f89e165c9b2df9789d) 32 | - DAI/USD (https://etherscan.io/address/0xaed0c38402a5d19df6e4c03f4e2dced6e29c1ee9) 33 | - USDT/USD (https://etherscan.io/address/0x3e7d1eab13ad0104d2750b8863b489d65364e32d) 34 | - USDC/USD (https://etherscan.io/address/0x8fffffd4afb6115b954bd326cbe7b4ba576818f6) 35 | - BUSD/USD (https://etherscan.io/address/0x833d8eb16d306ed1fbb5d7a2e019e106b960965a) 36 | - LINK/USD (https://etherscan.io/address/0x2c1d072e956affc0d435cb7ac38ef18d24d9127c) 37 | - UNI/USD (https://etherscan.io/address/0x553303d460ee0afb37edff9be42922d8ff63220e) 38 | - SUSHI/USD (https://etherscan.io/address/0xcc70f09a6cc17553b2e31954cd36e4a2d89501f7) 39 | - AAVE/USD (https://etherscan.io/address/0x547a514d5e3769680ce22b2361c10ea13619e8a9) 40 | - SNX/USD (https://etherscan.io/address/0xdc3ea94cd0ac27d9a86c180091e7f78c683d3699) 41 | 42 | # 🔗 subgraph api - 43 | - uniswapV2SubGraph.js (https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2) 44 | 45 | # 🛠 utils 46 | - [tokensnifferScrapper.js](https://tokensniffer.com/) - read tokens and save as json file 47 | - [etherscanScrapper.js](https://etherscan.io/accounts/label/compound) - read verified contracts and save as json file 48 | - [4byteEventsApi.js](https://www.4byte.directory/api/v1/event-signatures/?format=json) - read contracts event signatures and save as json file 49 | 50 | # 🛠 ethereum smart contracts utils 51 | - [mpoolPendingTxs.js] - subscribe mempool transactions 52 | - [findVerifiedContracts.js] - find verified contracts 53 | - [findVulContracts.js] - find smart contracts vulnerabilities (bytecode analyzer using Mythril:https://github.com/ConsenSys/mythril) 54 | - [findUniswapClones.js] - find uniswap v2 clones 55 | - [findFlashLoanTxs.js] - find uniswap v2 and v3 flash loans trxs 56 | - [findUniswapV2Txs.js] - find uniswap v2 liquidations trxs 57 | - [findUniswapV3Txs.js] - find uniswap v3 liquidations trxs 58 | - [findAaveV2Txs.js] - find aave v2 liquidations trxs 59 | 60 | # 🛠 token utils 61 | - [fetchTokens.js] - read tokens and save as json file (coingecko, 1inch, 0x, kyber) 62 | - [fetchMarketPairs.js] - read market pairs and save as json file (uniswap, sushiswap) 63 | - [findToken.js] - find token by address 64 | 65 | # 🛠 contract vanity address (create2) 66 | - [findVanityAddress.js] - find vanity address generator with leading zeros 67 | 68 | -------------------------------------------------------------------------------- /foundry/lib/forge-std/src/Vm.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Unlicense 2 | pragma solidity >=0.6.0; 3 | pragma experimental ABIEncoderV2; 4 | 5 | interface Vm { 6 | // Set block.timestamp (newTimestamp) 7 | function warp(uint256) external; 8 | // Set block.height (newHeight) 9 | function roll(uint256) external; 10 | // Set block.basefee (newBasefee) 11 | function fee(uint256) external; 12 | // Set block.chainid 13 | function chainId(uint256) external; 14 | // Loads a storage slot from an address (who, slot) 15 | function load(address,bytes32) external returns (bytes32); 16 | // Stores a value to an address' storage slot, (who, slot, value) 17 | function store(address,bytes32,bytes32) external; 18 | // Signs data, (privateKey, digest) => (v, r, s) 19 | function sign(uint256,bytes32) external returns (uint8,bytes32,bytes32); 20 | // Gets address for a given private key, (privateKey) => (address) 21 | function addr(uint256) external returns (address); 22 | // Gets the nonce of an account 23 | function getNonce(address) external returns (uint64); 24 | // Sets the nonce of an account; must be higher than the current nonce of the account 25 | function setNonce(address, uint64) external; 26 | // Performs a foreign function call via terminal, (stringInputs) => (result) 27 | function ffi(string[] calldata) external returns (bytes memory); 28 | // Sets the *next* call's msg.sender to be the input address 29 | function prank(address) external; 30 | // Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called 31 | function startPrank(address) external; 32 | // Sets the *next* call's msg.sender to be the input address, and the tx.origin to be the second input 33 | function prank(address,address) external; 34 | // Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called, and the tx.origin to be the second input 35 | function startPrank(address,address) external; 36 | // Resets subsequent calls' msg.sender to be `address(this)` 37 | function stopPrank() external; 38 | // Sets an address' balance, (who, newBalance) 39 | function deal(address, uint256) external; 40 | // Sets an address' code, (who, newCode) 41 | function etch(address, bytes calldata) external; 42 | // Expects an error on next call 43 | function expectRevert(bytes calldata) external; 44 | function expectRevert(bytes4) external; 45 | function expectRevert() external; 46 | // Record all storage reads and writes 47 | function record() external; 48 | // Gets all accessed reads and write slot from a recording session, for a given address 49 | function accesses(address) external returns (bytes32[] memory reads, bytes32[] memory writes); 50 | // Prepare an expected log with (bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData). 51 | // Call this function, then emit an event, then call a function. Internally after the call, we check if 52 | // logs were emitted in the expected order with the expected topics and data (as specified by the booleans) 53 | function expectEmit(bool,bool,bool,bool) external; 54 | // Mocks a call to an address, returning specified data. 55 | // Calldata can either be strict or a partial match, e.g. if you only 56 | // pass a Solidity selector to the expected calldata, then the entire Solidity 57 | // function will be mocked. 58 | function mockCall(address,bytes calldata,bytes calldata) external; 59 | // Clears all mocked calls 60 | function clearMockedCalls() external; 61 | // Expect a call to an address with the specified calldata. 62 | // Calldata can either be strict or a partial match 63 | function expectCall(address,bytes calldata) external; 64 | // Gets the code from an artifact file. Takes in the relative path to the json file 65 | function getCode(string calldata) external returns (bytes memory); 66 | // Labels an address in call traces 67 | function label(address, string calldata) external; 68 | // If the condition is false, discard this run's fuzz inputs and generate new ones 69 | function assume(bool) external; 70 | } 71 | -------------------------------------------------------------------------------- /token/fetchMarketPairs.js: -------------------------------------------------------------------------------- 1 | //npm install fs 2 | //npm install axios 3 | //npm install ethers 4 | 5 | //ex - node fetchMarketPairs.js 6 | 7 | const path = require('path'); 8 | require('dotenv').config({path:path.resolve('../', '.env')}); 9 | 10 | const fs = require('fs'); 11 | const axios = require('axios'); 12 | const { Contract, providers } = require("ethers"); 13 | 14 | const { INFURA_APIKEY } = process.env; 15 | 16 | const UNISWAP_LOOKUP_CONTRACT_ADDRESS = '0x5EF1009b9FCD4fec3094a5564047e190D72Bd511'; 17 | const UNISWAP_QUERY_ABI = [{ 18 | "inputs": [{ 19 | "internalType": "contract UniswapV2Factory", 20 | "name": "_uniswapFactory", 21 | "type": "address" 22 | }, {"internalType": "uint256", "name": "_start", "type": "uint256"}, { 23 | "internalType": "uint256", 24 | "name": "_stop", 25 | "type": "uint256" 26 | }], 27 | "name": "getPairsByIndexRange", 28 | "outputs": [{"internalType": "address[3][]", "name": "", "type": "address[3][]"}], 29 | "stateMutability": "view", 30 | "type": "function" 31 | }, { 32 | "inputs": [{"internalType": "contract IUniswapV2Pair[]", "name": "_pairs", "type": "address[]"}], 33 | "name": "getReservesByPairs", 34 | "outputs": [{"internalType": "uint256[3][]", "name": "", "type": "uint256[3][]"}], 35 | "stateMutability": "view", 36 | "type": "function" 37 | }]; 38 | 39 | const WETH_ADDRESS = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'; 40 | 41 | const ETHEREUM_RPC_URL = `https://mainnet.infura.io/v3/${INFURA_APIKEY}`; 42 | const provider = new providers.StaticJsonRpcProvider(ETHEREUM_RPC_URL); 43 | const uniswapQuery = new Contract(UNISWAP_LOOKUP_CONTRACT_ADDRESS, UNISWAP_QUERY_ABI, provider); 44 | 45 | const BATCH_COUNT_LIMIT = 100; 46 | const UNISWAP_BATCH_SIZE = 1000; 47 | 48 | const blacklistTokens = [ 49 | '0xD75EA151a61d06868E31F8988D28DFE5E9df57B4' 50 | ]; 51 | 52 | // "assets":[ 53 | // { 54 | // "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", 55 | // "balance": 60447.40919661198, 56 | // "name": "Wrapped Ether", 57 | // "symbol": "WETH", 58 | // "weight": 0.5 59 | // }, 60 | // { 61 | // "address": "0xdac17f958d2ee523a2206206994597c13d831ec7", 62 | // "balance": 117922963.245255, 63 | // "name": "Tether USD", 64 | // "symbol": "USDT", 65 | // "weight": 0.5 66 | // } 67 | // ], 68 | // "exchange": "0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852", 69 | 70 | const readMarkets = async (pf, factoryAddress) => { 71 | const marketPairs = []; 72 | for (let i = 0; i < BATCH_COUNT_LIMIT * UNISWAP_BATCH_SIZE; i += UNISWAP_BATCH_SIZE) { 73 | const pairs = (await uniswapQuery.functions.getPairsByIndexRange(factoryAddress, i, i + UNISWAP_BATCH_SIZE))[0]; 74 | for (let i = 0; i < pairs.length; i++) { 75 | const pair = pairs[i]; 76 | const marketAddress = pair[2]; 77 | let tokenAddress; 78 | 79 | if (pair[0] === WETH_ADDRESS) { 80 | tokenAddress = pair[1] 81 | } else if (pair[1] === WETH_ADDRESS) { 82 | tokenAddress = pair[0] 83 | } else { 84 | continue; 85 | } 86 | 87 | if (!blacklistTokens.includes(tokenAddress)) { 88 | const pairObj = { 89 | exchange: marketAddress, 90 | assets:[ 91 | { 92 | address:pair[0] 93 | }, 94 | { 95 | address:pair[1] 96 | } 97 | ] 98 | }; 99 | marketPairs.push(pairObj); 100 | } 101 | } 102 | if (pairs.length < UNISWAP_BATCH_SIZE) { 103 | break 104 | } 105 | } 106 | // console.log('marketPairs',marketPairs); 107 | 108 | if (!marketPairs) { 109 | console.error(`error fetching data from ${this.name}: ${error}`); 110 | return false; 111 | } else { 112 | console.log('writing files -- '); 113 | const data = { 114 | total:marketPairs.length, 115 | results:marketPairs 116 | }; 117 | fs.writeFile(`${__dirname}/json/${pf}-market-pairs.json`, JSON.stringify(data), console.error); 118 | return true; 119 | } 120 | } 121 | 122 | const SUSHISWAP_FACTORY_ADDRESS = '0xC0AEe478e3658e2610c5F7A4A2E1777cE9e4f2Ac'; 123 | const UNISWAP_FACTORY_ADDRESS = '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f'; 124 | const SHIBASWAP_FACTORY_ADDRESS = '0x115934131916c8b277dd010ee02de363c09d037c'; 125 | const FACTORY_ADDRESSES = [ 126 | UNISWAP_FACTORY_ADDRESS, 127 | SUSHISWAP_FACTORY_ADDRESS, 128 | SHIBASWAP_FACTORY_ADDRESS, 129 | ]; 130 | // readMarkets('uniswap-v2',UNISWAP_FACTORY_ADDRESS); 131 | // readMarkets('sushiswap',SUSHISWAP_FACTORY_ADDRESS); 132 | // readMarkets('shibaswap',SHIBASWAP_FACTORY_ADDRESS); 133 | 134 | -------------------------------------------------------------------------------- /foundry/lib/forge-std/src/test/StdCheats.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Unlicense 2 | pragma solidity >=0.6.0 <0.9.0; 3 | 4 | import "../Test.sol"; 5 | 6 | contract StdCheatsTest is Test { 7 | Bar test; 8 | 9 | function setUp() public { 10 | test = new Bar(); 11 | } 12 | 13 | function testSkip() public { 14 | vm.warp(100); 15 | skip(25); 16 | assertEq(block.timestamp, 125); 17 | } 18 | 19 | function testRewind() public { 20 | vm.warp(100); 21 | rewind(25); 22 | assertEq(block.timestamp, 75); 23 | } 24 | 25 | function testHoax() public { 26 | hoax(address(1337)); 27 | test.bar{value: 100}(address(1337)); 28 | } 29 | 30 | function testHoaxOrigin() public { 31 | hoax(address(1337), address(1337)); 32 | test.origin{value: 100}(address(1337)); 33 | } 34 | 35 | function testHoaxDifferentAddresses() public { 36 | hoax(address(1337), address(7331)); 37 | test.origin{value: 100}(address(1337), address(7331)); 38 | } 39 | 40 | function testStartHoax() public { 41 | startHoax(address(1337)); 42 | test.bar{value: 100}(address(1337)); 43 | test.bar{value: 100}(address(1337)); 44 | vm.stopPrank(); 45 | test.bar(address(this)); 46 | } 47 | 48 | function testStartHoaxOrigin() public { 49 | startHoax(address(1337), address(1337)); 50 | test.origin{value: 100}(address(1337)); 51 | test.origin{value: 100}(address(1337)); 52 | vm.stopPrank(); 53 | test.bar(address(this)); 54 | } 55 | 56 | function testDeal() public { 57 | deal(address(this), 1 ether); 58 | assertEq(address(this).balance, 1 ether); 59 | } 60 | 61 | function testDealToken() public { 62 | Bar barToken = new Bar(); 63 | address bar = address(barToken); 64 | deal(bar, address(this), 10000e18); 65 | assertEq(barToken.balanceOf(address(this)), 10000e18); 66 | } 67 | 68 | function testDealTokenAdjustTS() public { 69 | Bar barToken = new Bar(); 70 | address bar = address(barToken); 71 | deal(bar, address(this), 10000e18, true); 72 | assertEq(barToken.balanceOf(address(this)), 10000e18); 73 | assertEq(barToken.totalSupply(), 20000e18); 74 | deal(bar, address(this), 0, true); 75 | assertEq(barToken.balanceOf(address(this)), 0); 76 | assertEq(barToken.totalSupply(), 10000e18); 77 | } 78 | 79 | function testDeployCode() public { 80 | address deployed = deployCode("StdCheats.t.sol:StdCheatsTest", bytes("")); 81 | assertEq(string(getCode(deployed)), string(getCode(address(this)))); 82 | } 83 | 84 | function testDeployCodeNoArgs() public { 85 | address deployed = deployCode("StdCheats.t.sol:StdCheatsTest"); 86 | assertEq(string(getCode(deployed)), string(getCode(address(this)))); 87 | } 88 | 89 | function getCode(address who) internal view returns (bytes memory o_code) { 90 | /// @solidity memory-safe-assembly 91 | assembly { 92 | // retrieve the size of the code, this needs assembly 93 | let size := extcodesize(who) 94 | // allocate output byte array - this could also be done without assembly 95 | // by using o_code = new bytes(size) 96 | o_code := mload(0x40) 97 | // new "memory end" including padding 98 | mstore(0x40, add(o_code, and(add(add(size, 0x20), 0x1f), not(0x1f)))) 99 | // store length in memory 100 | mstore(o_code, size) 101 | // actually retrieve the code, this needs assembly 102 | extcodecopy(who, add(o_code, 0x20), 0, size) 103 | } 104 | } 105 | } 106 | 107 | contract Bar { 108 | constructor() { 109 | /// `DEAL` STDCHEAT 110 | totalSupply = 10000e18; 111 | balanceOf[address(this)] = totalSupply; 112 | } 113 | 114 | /// `HOAX` STDCHEATS 115 | function bar(address expectedSender) public payable { 116 | require(msg.sender == expectedSender, "!prank"); 117 | } 118 | function origin(address expectedSender) public payable { 119 | require(msg.sender == expectedSender, "!prank"); 120 | require(tx.origin == expectedSender, "!prank"); 121 | } 122 | function origin(address expectedSender, address expectedOrigin) public payable { 123 | require(msg.sender == expectedSender, "!prank"); 124 | require(tx.origin == expectedOrigin, "!prank"); 125 | } 126 | 127 | /// `DEAL` STDCHEAT 128 | mapping (address => uint256) public balanceOf; 129 | uint256 public totalSupply; 130 | } 131 | -------------------------------------------------------------------------------- /hardhat/findVerifiedContracts.js: -------------------------------------------------------------------------------- 1 | // findVerifiedContracts 2 | const path = require('path'); 3 | require('dotenv').config({path:path.resolve('../', '.env')}); 4 | 5 | const fs = require('fs'); 6 | const axios = require('axios'); 7 | const { providers, utils } = require("ethers"); 8 | const { inspect } = require('util'); 9 | 10 | const deepLogs = (obj) => { 11 | return inspect(obj, {depth: 5}); 12 | } 13 | 14 | const { INFURA_APIKEY, ARCHIVENODE_APIKEY, ETHERSCAN_APIKEY } = process.env; 15 | const ETHERSCAN_ABI_ENDPOINT = a => `https://api.etherscan.io/api?module=contract&action=getabi&address=${a}&apikey=${ETHERSCAN_APIKEY}`; 16 | 17 | // const ETHEREUM_RPC_URL = `https://mainnet.infura.io/v3/${INFURA_APIKEY}`; 18 | const ETHEREUM_RPC_URL = `https://api.archivenode.io/${ARCHIVENODE_APIKEY}`; 19 | 20 | const provider = new providers.StaticJsonRpcProvider(ETHEREUM_RPC_URL); 21 | // const provider = new providers.JsonRpcProvider(ETHEREUM_RPC_URL); 22 | // const provider = new providers.getDefaultProvider(ETHEREUM_RPC_URL); 23 | 24 | console.log('start --'); 25 | console.log('ETHEREUM_RPC_URL',ETHEREUM_RPC_URL); 26 | 27 | const getBlockNumber = async (n, debug) => { 28 | const blockNumber = await provider.getBlockNumber(); 29 | const blocksPerDay = 6600; 30 | LATEST_BLOCK = blockNumber; 31 | START_SCANNED_BLOCK = blockNumber - (n * blocksPerDay); 32 | if(debug) console.log('latest block',blockNumber); 33 | if(debug) console.log('blocks not scanned',START_SCANNED_BLOCK); 34 | readNumOfBlocks(START_SCANNED_BLOCK, 0, PENDING_BLOCK_SCANNED, 2000, true); 35 | return blockNumber; 36 | } 37 | 38 | const getBlock = async (blockNumber, debug) => { 39 | const block = await provider.getBlockWithTransactions(blockNumber); 40 | // if(debug) console.log('block',block); 41 | return block; 42 | } 43 | 44 | const getABI = async (a, debug) => { 45 | 46 | const api_url = ETHERSCAN_ABI_ENDPOINT(a); 47 | // if(debug) console.log('api -- ',api_url); 48 | 49 | const config = { 50 | timeout: 30000, 51 | url: api_url, 52 | method: 'get', 53 | responseType: 'json' 54 | }; 55 | const res = await axios(config); 56 | const data = res.data; 57 | // if(debug) console.log('data -- ',api_url, deepLogs(data) ); 58 | if(debug) { 59 | if(res.status != 200) console.log('res --', deepLogs(data) ); 60 | } 61 | return data; 62 | } 63 | 64 | const readBlock = async (blockNumber, debug) => { 65 | 66 | let contract_trs = []; 67 | if(debug) console.log('block',blockNumber); 68 | 69 | let block = await getBlock(blockNumber); 70 | let txs = block.transactions; 71 | let j=0; 72 | for(j=0;j 0){ 92 | contract_trs.map( async c => { 93 | let cobj = { 94 | "block":c.blockNumber, 95 | "hash": c.hash, 96 | "address": c.creates 97 | } 98 | let verifiedContractsArr = await require(`./json/verified-contracts-clones.json`); 99 | verifiedContractsArr.push(cobj); 100 | // if(debug) console.log('verifiedContractsArr ',verifiedContractsArr); 101 | 102 | // save verified contracts 103 | await fs.writeFile(`${__dirname}/json/verified-contracts-clones.json`, JSON.stringify(verifiedContractsArr), console.error); 104 | 105 | // save verified contract abi 106 | await fs.writeFile(`${__dirname}/json/${c.blockNumber}-${c.creates}.json`, JSON.stringify(c.ABI), console.error); 107 | 108 | }) 109 | } 110 | } 111 | 112 | const readNumOfBlocks = async (blockNumber, inc, num, inter, debug) => { 113 | setTimeout(() => { 114 | inc++; 115 | // if(debug) console.log('blockNumber' ,blockNumber+inc); 116 | blockNumber+inc < blockNumber+num ? readNumOfBlocks(blockNumber, inc, num, inter, debug) : null; 117 | readBlock(blockNumber+inc, true); 118 | },inter); 119 | } 120 | 121 | let LATEST_BLOCK = 0, START_SCANNED_BLOCK = 0, PENDING_BLOCK_SCANNED = 20000; 122 | 123 | getBlockNumber(3, true); 124 | // readNumOfBlocks(14203083-1, 0, 1, 2000, true); 125 | 126 | module.exports = { 127 | readNumOfBlocks 128 | } 129 | return; 130 | 131 | -------------------------------------------------------------------------------- /hardhat/findVanityAddress.js: -------------------------------------------------------------------------------- 1 | // findVanityAddress 2 | const path = require('path'); 3 | require('dotenv').config({path:path.resolve('../', '.env')}); 4 | const fs = require('fs'); 5 | 6 | const axios = require('axios'); 7 | const { providers, utils, Wallet } = require("ethers"); 8 | const { artifacts, ethers } = require("hardhat"); 9 | const { inspect } = require('util'); 10 | 11 | const deepLogs = (obj) => { 12 | return inspect(obj, {depth: 5}); 13 | } 14 | 15 | const { INFURA_APIKEY, ARCHIVENODE_APIKEY, ETHERSCAN_APIKEY } = process.env; 16 | const ETHERSCAN_ABI_ENDPOINT = a => `https://api.etherscan.io/api?module=contract&action=getabi&address=${a}&apikey=${ETHERSCAN_APIKEY}`; 17 | 18 | // const ETHEREUM_RPC_URL = `https://mainnet.infura.io/v3/${INFURA_APIKEY}`; 19 | const ETHEREUM_RPC_URL = `https://api.archivenode.io/${ARCHIVENODE_APIKEY}`; 20 | 21 | const provider = new providers.StaticJsonRpcProvider(ETHEREUM_RPC_URL); 22 | // const provider = new providers.JsonRpcProvider(ETHEREUM_RPC_URL); 23 | // const provider = new providers.getDefaultProvider(ETHEREUM_RPC_URL); 24 | 25 | console.log('start --'); 26 | console.log('ETHEREUM_RPC_URL',ETHEREUM_RPC_URL); 27 | 28 | const getBlock = async (blockNumber, debug) => { 29 | const block = await provider.getBlockWithTransactions(blockNumber); 30 | // if(debug) console.log('block',block); 31 | return block; 32 | } 33 | 34 | const buildCreate2Address = async (creatorAddress, saltHex, byteCode, debug) => { 35 | try{ 36 | let c; 37 | c = utils.getAddress( 38 | '0x' + 39 | utils.solidityKeccak256( 40 | ['bytes'], 41 | [ 42 | `0xff${ 43 | creatorAddress.slice(2) 44 | }${ 45 | saltHex.slice(2) 46 | }${ 47 | byteCode.slice(2) 48 | }`, 49 | ] 50 | ).slice(-40) 51 | ); 52 | 53 | // c = utils.getAddress( 54 | // '0x' + 55 | // utils.solidityKeccak256( 56 | // ['bytes'], 57 | // [ 58 | // `0xff${creatorAddress.slice(2)}${saltHex.slice( 59 | // 2 60 | // )}${utils.solidityKeccak256(['bytes'], [byteCode]).slice(2)}`, 61 | // ] 62 | // ).slice(-40) 63 | // ); 64 | 65 | if(debug) console.log(c); 66 | return c; 67 | } catch (e){ 68 | console.log(e); 69 | } 70 | } 71 | 72 | const getCreate2Address = async (creatorAddress, saltHex, byteCode, debug) => { 73 | try{ 74 | let c; 75 | c = await utils.getCreate2Address(creatorAddress, saltHex, byteCode); 76 | // c = await buildCreate2Address(creatorAddress, saltHex, byteCode); 77 | // if(debug) console.log('create2 ', c); 78 | return c; 79 | } catch (e){ 80 | console.log(e); 81 | } 82 | } 83 | 84 | const getSalt = async (inc, debug) => { 85 | try{ 86 | let s = inc; 87 | // s = await utils.formatBytes32String(s); 88 | // s = await utils.keccak256(utils.toUtf8Bytes(s)); 89 | s = utils.hexlify(utils.hexZeroPad(s, 32)); 90 | // if(debug) console.log('salt ', s, utils.isHexString(s)); 91 | return s; 92 | } catch (e){ 93 | console.log(e); 94 | } 95 | } 96 | 97 | const getByteCode = async (c, debug) => { 98 | try{ 99 | let bc; 100 | bc = await artifacts.readArtifact(c); 101 | bc = bc.bytecode; 102 | bc = utils.solidityKeccak256(['bytes'], [bc]); 103 | // if(debug) console.log('byteCode', bc, utils.isHexString(bc)); 104 | return bc ? bc : null; 105 | } catch (e){ 106 | console.log(e); 107 | } 108 | }; 109 | 110 | const runVanityAddress = async (creatorAddress, contractName, z, inc, num, debug) => { 111 | let c2Arr= [] 112 | let c2 = "",c2m = 0; 113 | let saltHex = ""; 114 | let byteCode = await getByteCode(contractName, debug); 115 | 116 | num = inc+num; 117 | 118 | for(inc; inc < num;) { 119 | inc++; 120 | saltHex = await getSalt(inc, debug); 121 | c2 = await getCreate2Address(creatorAddress, saltHex, byteCode, debug); 122 | // c2 = c2.substring(2,7); 123 | c2m = c2.substring(2,7).match(/^0+/); 124 | c2m = c2m ? c2m[0].length : 0; 125 | if(c2m >= z){ 126 | c2Arr.push({ 127 | salt:inc, 128 | address:c2 129 | }) 130 | } 131 | }; 132 | console.log('c2Arr', inc, c2Arr); 133 | } 134 | 135 | // sample contract ./YourContract.sol 136 | // npx hardhat compile 137 | 138 | // const contractCode = `contract YourContract { 139 | // event SetPurpose(address sender, string purpose); 140 | // string public purpose = "Building Unstoppable Apps!!!"; 141 | // constructor() payable { 142 | // // what should we do on deploy? 143 | // } 144 | // function setPurpose(string memory newPurpose) public { 145 | // purpose = newPurpose; 146 | // // console.log(msg.sender,"set purpose to",purpose); 147 | // emit SetPurpose(msg.sender, purpose); 148 | // } 149 | // // to support receiving ETH by default 150 | // receive() external payable {} 151 | // fallback() external payable {} 152 | // }`; 153 | 154 | const contractOwnerAddress = Wallet.createRandom().address; 155 | // const contractOwnerAddress = new ethers.Wallet("0x0123456789012345678901234567890123456789012345678901234567890123").address; 156 | const contractName = "YourContract"; 157 | const leadingZeros = 4; 158 | 159 | runVanityAddress(contractOwnerAddress, contractName, leadingZeros, 1, 500000, true); 160 | 161 | module.exports = { 162 | runVanityAddress 163 | } 164 | return; 165 | 166 | -------------------------------------------------------------------------------- /api/oneInchQuote.js: -------------------------------------------------------------------------------- 1 | //npm install fs 2 | //npm install axios 3 | 4 | //ex - node oneInchQuote.js 5 | 6 | const axios = require('axios'); 7 | const { inspect } = require('util'); 8 | 9 | const deepLogs = (obj) => { 10 | return inspect(obj, {depth: 5}); 11 | } 12 | 13 | // const protocols = [ 14 | // "AAVE", 15 | // "AAVE_LIQUIDATOR", 16 | // "AAVE_V2", 17 | // "BALANCER", 18 | // "BALANCER_V2", 19 | // "BANCOR", 20 | // "BLACKHOLESWAP", 21 | // "CHAI", 22 | // "COFIX", 23 | // "COMPOUND", 24 | // "CONVERGENCE_X", 25 | // "CREAMSWAP", 26 | // "CREAM_LENDING", 27 | // "CURVE", 28 | // "CURVE_V2", 29 | // "DEFISWAP", 30 | // "DFX_FINANCE", 31 | // "DODO", 32 | // "DODO_V2", 33 | // "IEARN", 34 | // "INDEXED_FINANCE", 35 | // "KYBER", 36 | // "KYBER_DMM", 37 | // "LINKSWAP", 38 | // "LUASWAP", 39 | // "MINISWAP", 40 | // "MOONISWAP", 41 | // "MSTABLE", 42 | // "OASIS", 43 | // "ONE_INCH_LIMIT_ORDER", 44 | // "ONE_INCH_LP", 45 | // "ONE_INCH_LP_1_1", 46 | // "ONE_INCH_LP_MIGRATOR", 47 | // "ONE_INCH_LP_MIGRATOR_V1_1", 48 | // "PMM1", 49 | // "PMM2", 50 | // "PMM3", 51 | // "PMM4", 52 | // "POWERINDEX", 53 | // "PSM", 54 | // "SADDLE", 55 | // "SAKESWAP", 56 | // "SETH_WRAPPER", 57 | // "SHELL", 58 | // "SMOOTHY_FINANCE", 59 | // "ST_ETH", 60 | // "SUSHI", 61 | // "SUSHISWAP_MIGRATOR", 62 | // "SWERVE", 63 | // "SYNTHETIX", 64 | // "S_FINANCE", 65 | // "UNISWAP_V1", 66 | // "UNISWAP_V2", 67 | // "UNISWAP_V2_MIGRATOR", 68 | // "UNISWAP_V3", 69 | // "VALUELIQUID", 70 | // "WETH", 71 | // "XSIGMA", 72 | // "ZRX" 73 | // ]; 74 | 75 | const protocols = [ 76 | // "UNISWAP_V1", 77 | "UNISWAP_V2", 78 | // "UNISWAP_V3", 79 | "SUSHI", 80 | // "KYBER", 81 | "KYBER_DMM", 82 | // "BALANCER", 83 | "BALANCER_V2", 84 | "BANCOR", 85 | "CREAMSWAP", 86 | // "AAVE", 87 | "AAVE_V2", 88 | "COMPOUND", 89 | // "CURVE", 90 | "CURVE_V2", 91 | // "DEFISWAP", 92 | "SYNTHETIX", 93 | ]; 94 | 95 | const quoteApi = (from, to, amt, plat) => `https://api.1inch.exchange/v3.0/1/quote?fromTokenAddress=${from}&toTokenAddress=${to}&amount=${amt}&protocols=${plat}`; 96 | let config = { 97 | timeout: 30000, 98 | url: '', 99 | method: 'get', 100 | responseType: 'json' 101 | }; 102 | 103 | const getQuote = async (from, to, amt, dec, plat1, plat2, debug) => { 104 | 105 | let platres1,platdata1,fromamt1,amt1; 106 | let platres2,platdata2,fromamt2,amt2,dec2; 107 | 108 | const platurl1 = quoteApi(from,to,amt+dec,plat1); 109 | config.url = platurl1; 110 | // if(debug) console.log(platurl1); 111 | 112 | try{ 113 | platres1 = await axios(config); 114 | platdata1 = platres1.data; 115 | if(!platdata1.error){ 116 | fromamt1 = platdata1.fromTokenAmount; 117 | amt1 = platdata1.toTokenAmount; 118 | } 119 | } catch (e){ 120 | console.log(e.response.data); 121 | return; 122 | } 123 | 124 | const platurl2 = quoteApi(to,from,amt1,plat2); 125 | config.url = platurl2; 126 | // if(debug) console.log(platurl2); 127 | 128 | try{ 129 | platres2 = await axios(config); 130 | platdata2 = platres2.data; 131 | if(!platdata2.error){ 132 | fromamt2 = platdata2.fromTokenAmount; 133 | amt2 = platdata2.toTokenAmount; 134 | dec2 = platdata2.toToken.decimals; 135 | } 136 | } catch (e){ 137 | console.log(e.response.data); 138 | } 139 | 140 | if (!platdata1 || !platdata2) { 141 | console.error(`error fetching data from ${this.name}: ${platdata1}`); 142 | console.error(`error fetching data from ${this.name}: ${platdata2}`); 143 | return false; 144 | } else { 145 | 146 | // if(debug) console.log('platdata1 -- ',deepLogs(platdata1)); 147 | // if(debug) console.log('platdata2 -- ',deepLogs(platdata2)); 148 | if(debug) { 149 | let obj = { 150 | 'plat': plat1 , 151 | 'from-amt': fromamt1, 152 | 'to-amt': amt1, 153 | 'plat-2': plat2 154 | } 155 | let obj2= { 156 | 'plat': plat2 , 157 | 'from-amt': fromamt2, 158 | 'to-amt': amt2 159 | } 160 | let obj3 = { 161 | 'profit': amt2-fromamt1, 162 | 'eth-profit': parseFloat((amt2-fromamt1)/_e).toFixed(2) 163 | } 164 | if(amt2-fromamt1 > 0 ){ 165 | profitTrades.push(obj); 166 | profitTrades.push(obj2); 167 | profitTrades.push(obj3); 168 | } else { 169 | losingTrades.push(obj); 170 | losingTrades.push(obj2); 171 | losingTrades.push(obj3); 172 | } 173 | 174 | } 175 | return true; 176 | } 177 | } 178 | 179 | let _dec = '000000000000000000'; 180 | let _e = 1000000000000000000; 181 | let _showProfit = true; 182 | let _showlosing = true; 183 | let profitTrades = [], losingTrades = []; 184 | 185 | const weth_add = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"; 186 | const dai_add = "0x6B175474E89094C44Da98b954EedeAC495271d0F"; 187 | const usdt_add = "0xdac17f958d2ee523a2206206994597c13d831ec7"; 188 | const usdc_add = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"; 189 | const wbtc_add = "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599"; 190 | 191 | const seth_add = "0x57ab1ec28d129707052df4df418d58a2d46d5f51"; 192 | 193 | let _amt = 1, _inc = 1; 194 | const _plat1 = "UNISWAP_V2", _plat2 = "SUSHI"; 195 | 196 | const runQuotes = async (debug) => { 197 | 198 | for(let _p1=0;_p1 { 11 | return inspect(obj, {depth: 5}); 12 | } 13 | 14 | const findMatches = (clone, org, debug) => { 15 | const clone_filter = clone.filter( a => { 16 | return a.type == 'function' ? true : false; 17 | }) 18 | const org_filter = org.filter( b => { 19 | return b.type == 'function' ? true : false; 20 | }) 21 | // if(debug) console.log('abi fn filter',clone_filter, org_filter); 22 | 23 | const finds = org_filter.filter( j => { 24 | return clone_filter.some( k => { 25 | // if(debug) console.log('j.name == k.name', j.name, k.name); 26 | return j.name == k.name ? true : false; 27 | }); 28 | }); 29 | // if(debug) console.log('finds',finds); 30 | return finds; 31 | } 32 | const arrayUnique = (array) => { 33 | var a = array.concat(); 34 | for(var i=0; i `https://api.etherscan.io/api?module=contract&action=getabi&address=${a}&apikey=${ETHERSCAN_APIKEY}`; 95 | 96 | // const ETHEREUM_RPC_URL = `https://mainnet.infura.io/v3/${INFURA_APIKEY}`; 97 | const ETHEREUM_RPC_URL = `https://api.archivenode.io/${ARCHIVENODE_APIKEY}`; 98 | 99 | const provider = new providers.StaticJsonRpcProvider(ETHEREUM_RPC_URL); 100 | // const provider = new providers.JsonRpcProvider(ETHEREUM_RPC_URL); 101 | // const provider = new providers.getDefaultProvider(ETHEREUM_RPC_URL); 102 | 103 | console.log('start --'); 104 | console.log('ETHEREUM_RPC_URL',ETHEREUM_RPC_URL); 105 | 106 | const getBlockNumber = async (n, debug) => { 107 | const blockNumber = await provider.getBlockNumber(); 108 | const blocksPerDay = 6600; 109 | LATEST_BLOCK = blockNumber; 110 | START_SCANNED_BLOCK = blockNumber - (n * blocksPerDay); 111 | if(debug) console.log('latest block',blockNumber); 112 | if(debug) console.log('blocks not scanned',START_SCANNED_BLOCK); 113 | readNumOfBlocks(START_SCANNED_BLOCK, 0, PENDING_BLOCK_SCANNED, 3000, true); 114 | return blockNumber; 115 | } 116 | 117 | const getBlock = async (blockNumber, debug) => { 118 | const block = await provider.getBlockWithTransactions(blockNumber); 119 | // if(debug) console.log('block',block); 120 | return block; 121 | } 122 | const getTxRc = async (hash, debug) => { 123 | const tx = await provider.getTransactionReceipt(hash); 124 | if(debug) console.log('tx',tx); 125 | return tx; 126 | } 127 | 128 | const getABI = async (a, debug) => { 129 | 130 | const api_url = ETHERSCAN_ABI_ENDPOINT(a); 131 | // if(debug) console.log('api -- ',api_url); 132 | 133 | const config = { 134 | timeout: 30000, 135 | url: api_url, 136 | method: 'get', 137 | responseType: 'json' 138 | }; 139 | const res = await axios(config); 140 | const data = res.data; 141 | // if(debug) console.log('data -- ',api_url, deepLogs(data) ); 142 | if(debug) { 143 | if(res.status != 200) console.log('res --', deepLogs(data) ); 144 | } 145 | return data; 146 | } 147 | 148 | const readBlock = async (blockNumber, debug) => { 149 | 150 | let contract_trs = []; 151 | 152 | if(debug) console.log('block',blockNumber); 153 | 154 | let block = await getBlock(blockNumber); 155 | let txs = block.transactions; 156 | let j=0; 157 | for(j=0;j 0){ 174 | contract_trs.map( async c => { 175 | let cobj = { 176 | "block":c.blockNumber, 177 | "hash": c.hash, 178 | "address": c.to, 179 | "input": c.decodeMethod 180 | } 181 | let clonesArr = await require(`./json/aavev2-liquidations-trxs.json`); 182 | clonesArr.push(cobj); 183 | // if(debug) console.log('clonesArr ',clonesArr); 184 | await fs.writeFile(`${__dirname}/json/aavev2-liquidations-trxs.json`, JSON.stringify(clonesArr), console.error); 185 | }) 186 | } 187 | } 188 | 189 | const readNumOfBlocks = async (blockNumber, inc, num, inter, debug) => { 190 | setTimeout(() => { 191 | inc++; 192 | // if(debug) console.log('blockNumber' ,blockNumber+inc); 193 | blockNumber+inc < blockNumber+num ? readNumOfBlocks(blockNumber, inc, num, inter, debug) : null; 194 | readBlock(blockNumber+inc, true); 195 | },inter); 196 | } 197 | 198 | let LATEST_BLOCK = 0, START_SCANNED_BLOCK = 0, PENDING_BLOCK_SCANNED = 10000; 199 | 200 | getBlockNumber(1, true); 201 | // readNumOfBlocks(14874872-1, 0, 1, 2000, true); 202 | 203 | // scanned aave v2 liquidation trx 204 | // "block": , 205 | // "hash": "", 206 | // "address": "", 207 | 208 | module.exports = { 209 | readNumOfBlocks 210 | } 211 | return; 212 | 213 | -------------------------------------------------------------------------------- /foundry/lib/ds-test/demo/demo.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity >=0.4.23; 3 | 4 | import "../src/test.sol"; 5 | 6 | contract DemoTest is DSTest { 7 | function test_this() public pure { 8 | require(true); 9 | } 10 | function test_logs() public { 11 | emit log("-- log(string)"); 12 | emit log("a string"); 13 | 14 | emit log("-- log_named_uint(string, uint)"); 15 | log_named_uint("uint", 512); 16 | 17 | emit log("-- log_named_int(string, int)"); 18 | log_named_int("int", -512); 19 | 20 | emit log("-- log_named_address(string, address)"); 21 | log_named_address("address", address(this)); 22 | 23 | emit log("-- log_named_bytes32(string, bytes32)"); 24 | log_named_bytes32("bytes32", "a string"); 25 | 26 | emit log("-- log_named_bytes(string, bytes)"); 27 | log_named_bytes("bytes", hex"cafefe"); 28 | 29 | emit log("-- log_named_string(string, string)"); 30 | log_named_string("string", "a string"); 31 | 32 | emit log("-- log_named_decimal_uint(string, uint, uint)"); 33 | log_named_decimal_uint("decimal uint", 1.0e18, 18); 34 | 35 | emit log("-- log_named_decimal_int(string, int, uint)"); 36 | log_named_decimal_int("decimal int", -1.0e18, 18); 37 | } 38 | event log_old_named_uint(bytes32,uint); 39 | function test_old_logs() public { 40 | log_old_named_uint("key", 500); 41 | log_named_bytes32("bkey", "val"); 42 | } 43 | function test_trace() public view { 44 | this.echo("string 1", "string 2"); 45 | } 46 | function test_multiline() public { 47 | emit log("a multiline\\n" "string"); 48 | emit log("a multiline " "string"); 49 | log_bytes("a string"); 50 | log_bytes("a multiline\n" "string"); 51 | log_bytes("a multiline\\n" "string"); 52 | emit log(unicode"Ώ"); 53 | logs(hex"0000"); 54 | log_named_bytes("0x0000", hex"0000"); 55 | logs(hex"ff"); 56 | } 57 | function echo(string memory s1, string memory s2) public pure 58 | returns (string memory, string memory) 59 | { 60 | return (s1, s2); 61 | } 62 | 63 | function prove_this(uint x) public { 64 | log_named_uint("sym x", x); 65 | assertGt(x + 1, 0); 66 | } 67 | 68 | function test_logn() public { 69 | assembly { 70 | log0(0x01, 0x02) 71 | log1(0x01, 0x02, 0x03) 72 | log2(0x01, 0x02, 0x03, 0x04) 73 | log3(0x01, 0x02, 0x03, 0x04, 0x05) 74 | } 75 | } 76 | 77 | event MyEvent(uint, uint indexed, uint, uint indexed); 78 | function test_events() public { 79 | emit MyEvent(1, 2, 3, 4); 80 | } 81 | 82 | function test_asserts() public { 83 | string memory err = "this test has failed!"; 84 | emit log("## assertTrue(bool)\n"); 85 | assertTrue(false); 86 | emit log("\n"); 87 | assertTrue(false, err); 88 | 89 | emit log("\n## assertEq(address,address)\n"); 90 | assertEq(address(this), msg.sender); 91 | emit log("\n"); 92 | assertEq(address(this), msg.sender, err); 93 | 94 | emit log("\n## assertEq32(bytes32,bytes32)\n"); 95 | assertEq32("bytes 1", "bytes 2"); 96 | emit log("\n"); 97 | assertEq32("bytes 1", "bytes 2", err); 98 | 99 | emit log("\n## assertEq(bytes32,bytes32)\n"); 100 | assertEq32("bytes 1", "bytes 2"); 101 | emit log("\n"); 102 | assertEq32("bytes 1", "bytes 2", err); 103 | 104 | emit log("\n## assertEq(uint,uint)\n"); 105 | assertEq(uint(0), 1); 106 | emit log("\n"); 107 | assertEq(uint(0), 1, err); 108 | 109 | emit log("\n## assertEq(int,int)\n"); 110 | assertEq(-1, -2); 111 | emit log("\n"); 112 | assertEq(-1, -2, err); 113 | 114 | emit log("\n## assertEqDecimal(int,int,uint)\n"); 115 | assertEqDecimal(-1.0e18, -1.1e18, 18); 116 | emit log("\n"); 117 | assertEqDecimal(-1.0e18, -1.1e18, 18, err); 118 | 119 | emit log("\n## assertEqDecimal(uint,uint,uint)\n"); 120 | assertEqDecimal(uint(1.0e18), 1.1e18, 18); 121 | emit log("\n"); 122 | assertEqDecimal(uint(1.0e18), 1.1e18, 18, err); 123 | 124 | emit log("\n## assertGt(uint,uint)\n"); 125 | assertGt(uint(0), 0); 126 | emit log("\n"); 127 | assertGt(uint(0), 0, err); 128 | 129 | emit log("\n## assertGt(int,int)\n"); 130 | assertGt(-1, -1); 131 | emit log("\n"); 132 | assertGt(-1, -1, err); 133 | 134 | emit log("\n## assertGtDecimal(int,int,uint)\n"); 135 | assertGtDecimal(-2.0e18, -1.1e18, 18); 136 | emit log("\n"); 137 | assertGtDecimal(-2.0e18, -1.1e18, 18, err); 138 | 139 | emit log("\n## assertGtDecimal(uint,uint,uint)\n"); 140 | assertGtDecimal(uint(1.0e18), 1.1e18, 18); 141 | emit log("\n"); 142 | assertGtDecimal(uint(1.0e18), 1.1e18, 18, err); 143 | 144 | emit log("\n## assertGe(uint,uint)\n"); 145 | assertGe(uint(0), 1); 146 | emit log("\n"); 147 | assertGe(uint(0), 1, err); 148 | 149 | emit log("\n## assertGe(int,int)\n"); 150 | assertGe(-1, 0); 151 | emit log("\n"); 152 | assertGe(-1, 0, err); 153 | 154 | emit log("\n## assertGeDecimal(int,int,uint)\n"); 155 | assertGeDecimal(-2.0e18, -1.1e18, 18); 156 | emit log("\n"); 157 | assertGeDecimal(-2.0e18, -1.1e18, 18, err); 158 | 159 | emit log("\n## assertGeDecimal(uint,uint,uint)\n"); 160 | assertGeDecimal(uint(1.0e18), 1.1e18, 18); 161 | emit log("\n"); 162 | assertGeDecimal(uint(1.0e18), 1.1e18, 18, err); 163 | 164 | emit log("\n## assertLt(uint,uint)\n"); 165 | assertLt(uint(0), 0); 166 | emit log("\n"); 167 | assertLt(uint(0), 0, err); 168 | 169 | emit log("\n## assertLt(int,int)\n"); 170 | assertLt(-1, -1); 171 | emit log("\n"); 172 | assertLt(-1, -1, err); 173 | 174 | emit log("\n## assertLtDecimal(int,int,uint)\n"); 175 | assertLtDecimal(-1.0e18, -1.1e18, 18); 176 | emit log("\n"); 177 | assertLtDecimal(-1.0e18, -1.1e18, 18, err); 178 | 179 | emit log("\n## assertLtDecimal(uint,uint,uint)\n"); 180 | assertLtDecimal(uint(2.0e18), 1.1e18, 18); 181 | emit log("\n"); 182 | assertLtDecimal(uint(2.0e18), 1.1e18, 18, err); 183 | 184 | emit log("\n## assertLe(uint,uint)\n"); 185 | assertLe(uint(1), 0); 186 | emit log("\n"); 187 | assertLe(uint(1), 0, err); 188 | 189 | emit log("\n## assertLe(int,int)\n"); 190 | assertLe(0, -1); 191 | emit log("\n"); 192 | assertLe(0, -1, err); 193 | 194 | emit log("\n## assertLeDecimal(int,int,uint)\n"); 195 | assertLeDecimal(-1.0e18, -1.1e18, 18); 196 | emit log("\n"); 197 | assertLeDecimal(-1.0e18, -1.1e18, 18, err); 198 | 199 | emit log("\n## assertLeDecimal(uint,uint,uint)\n"); 200 | assertLeDecimal(uint(2.0e18), 1.1e18, 18); 201 | emit log("\n"); 202 | assertLeDecimal(uint(2.0e18), 1.1e18, 18, err); 203 | 204 | emit log("\n## assertEq(string,string)\n"); 205 | string memory s1 = "string 1"; 206 | string memory s2 = "string 2"; 207 | assertEq(s1, s2); 208 | emit log("\n"); 209 | assertEq(s1, s2, err); 210 | 211 | emit log("\n## assertEq0(bytes,bytes)\n"); 212 | assertEq0(hex"abcdef01", hex"abcdef02"); 213 | log("\n"); 214 | assertEq0(hex"abcdef01", hex"abcdef02", err); 215 | } 216 | } 217 | 218 | contract DemoTestWithSetUp { 219 | function setUp() public { 220 | } 221 | function test_pass() public pure { 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /chainlinkPrices.js: -------------------------------------------------------------------------------- 1 | // chanlinkPrices 2 | require('dotenv').config(); 3 | const axios = require('axios'); 4 | const { Contract, providers, utils } = require("ethers"); 5 | const { inspect } = require('util'); 6 | 7 | const deepLogs = (obj) => { 8 | return inspect(obj, {depth: 5}); 9 | } 10 | 11 | const { INFURA_APIKEY, ARCHIVENODE_APIKEY } = process.env; 12 | 13 | // const ETHEREUM_RPC_URL = `https://mainnet.infura.io/v3/${INFURA_APIKEY}`; 14 | const ETHEREUM_RPC_URL = `https://api.archivenode.io/${ARCHIVENODE_APIKEY}`; 15 | const provider = new providers.StaticJsonRpcProvider(ETHEREUM_RPC_URL); 16 | 17 | const CHAINLINK_PRICEFEED_ABI = [{ "inputs": [], "name": "decimals", "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "description", "outputs": [{ "internalType": "string", "name": "", "type": "string" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "uint80", "name": "_roundId", "type": "uint80" }], "name": "getRoundData", "outputs": [{ "internalType": "uint80", "name": "roundId", "type": "uint80" }, { "internalType": "int256", "name": "answer", "type": "int256" }, { "internalType": "uint256", "name": "startedAt", "type": "uint256" }, { "internalType": "uint256", "name": "updatedAt", "type": "uint256" }, { "internalType": "uint80", "name": "answeredInRound", "type": "uint80" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "latestRoundData", "outputs": [{ "internalType": "uint80", "name": "roundId", "type": "uint80" }, { "internalType": "int256", "name": "answer", "type": "int256" }, { "internalType": "uint256", "name": "startedAt", "type": "uint256" }, { "internalType": "uint256", "name": "updatedAt", "type": "uint256" }, { "internalType": "uint80", "name": "answeredInRound", "type": "uint80" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "version", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }]; 18 | 19 | const CHAINLINK_ETHUSD_CONTRACT_ADDRESS = "0x5f4ec3df9cbd43714fe2740f5e3616155c5b8419"; 20 | const CHAINLINK_BTCUSD_CONTRACT_ADDRESS = "0xf4030086522a5beea4988f8ca5b36dbc97bee88c"; 21 | const CHAINLINK_BCHUSD_CONTRACT_ADDRESS = "0x9f0f69428f923d6c95b781f89e165c9b2df9789d"; 22 | 23 | const CHAINLINK_DAIUSD_CONTRACT_ADDRESS = "0xaed0c38402a5d19df6e4c03f4e2dced6e29c1ee9"; 24 | const CHAINLINK_USDTUSD_CONTRACT_ADDRESS = "0x3e7d1eab13ad0104d2750b8863b489d65364e32d"; 25 | const CHAINLINK_USDCUSD_CONTRACT_ADDRESS = "0x8fffffd4afb6115b954bd326cbe7b4ba576818f6"; 26 | const CHAINLINK_BUSDUSD_CONTRACT_ADDRESS = "0x833d8eb16d306ed1fbb5d7a2e019e106b960965a"; 27 | 28 | const CHAINLINK_LINKUSD_CONTRACT_ADDRESS = "0x2c1d072e956affc0d435cb7ac38ef18d24d9127c"; 29 | const CHAINLINK_UNIUSD_CONTRACT_ADDRESS = "0x553303d460ee0afb37edff9be42922d8ff63220e"; 30 | const CHAINLINK_SUSHIUSD_CONTRACT_ADDRESS = "0xcc70f09a6cc17553b2e31954cd36e4a2d89501f7"; 31 | const CHAINLINK_AAVEUSD_CONTRACT_ADDRESS = "0x547a514d5e3769680ce22b2361c10ea13619e8a9"; 32 | const CHAINLINK_SNXUSD_CONTRACT_ADDRESS = "0xdc3ea94cd0ac27d9a86c180091e7f78c683d3699"; 33 | 34 | // const CHAINLINK_BNBUSD_CONTRACT_ADDRESS = "0x0567f2323251f0aab15c8dfb1967e4e8a7d42aee"; 35 | 36 | const chainLinkETHUSD = new Contract(CHAINLINK_ETHUSD_CONTRACT_ADDRESS, CHAINLINK_PRICEFEED_ABI, provider); 37 | const chainLinkBTCUSD = new Contract(CHAINLINK_BTCUSD_CONTRACT_ADDRESS, CHAINLINK_PRICEFEED_ABI, provider); 38 | const chainLinkBCHUSD = new Contract(CHAINLINK_BCHUSD_CONTRACT_ADDRESS, CHAINLINK_PRICEFEED_ABI, provider); 39 | 40 | const chainLinkDAIUSD = new Contract(CHAINLINK_DAIUSD_CONTRACT_ADDRESS, CHAINLINK_PRICEFEED_ABI, provider); 41 | const chainLinkUSDTUSD = new Contract(CHAINLINK_USDTUSD_CONTRACT_ADDRESS, CHAINLINK_PRICEFEED_ABI, provider); 42 | const chainLinkUSDCUSD = new Contract(CHAINLINK_USDCUSD_CONTRACT_ADDRESS, CHAINLINK_PRICEFEED_ABI, provider); 43 | const chainLinkBUSDUSD = new Contract(CHAINLINK_BUSDUSD_CONTRACT_ADDRESS, CHAINLINK_PRICEFEED_ABI, provider); 44 | 45 | const chainLinkLINKUSD = new Contract(CHAINLINK_LINKUSD_CONTRACT_ADDRESS, CHAINLINK_PRICEFEED_ABI, provider); 46 | const chainLinkUNIUSD = new Contract(CHAINLINK_UNIUSD_CONTRACT_ADDRESS, CHAINLINK_PRICEFEED_ABI, provider); 47 | const chainLinkSUSHIUSD = new Contract(CHAINLINK_SUSHIUSD_CONTRACT_ADDRESS, CHAINLINK_PRICEFEED_ABI, provider); 48 | const chainLinkAAVEUSD = new Contract(CHAINLINK_AAVEUSD_CONTRACT_ADDRESS, CHAINLINK_PRICEFEED_ABI, provider); 49 | const chainLinkSNXUSD = new Contract(CHAINLINK_SNXUSD_CONTRACT_ADDRESS, CHAINLINK_PRICEFEED_ABI, provider); 50 | 51 | // const chainLinkBNBUSD = new Contract(CHAINLINK_BNBUSD_CONTRACT_ADDRESS, CHAINLINK_PRICEFEED_ABI, provider); 52 | 53 | const getPriceFeed = async (coin, feed, debug) => { 54 | 55 | const data = await feed.functions.latestRoundData(); 56 | const dataObj = { 57 | "roundId": data[0], 58 | "answer": data[1], 59 | "startedAt": data[2], 60 | "updatedAt": data[3], 61 | } 62 | dataObj.roundId = dataObj.roundId.toString(); 63 | dataObj.startedAt = dataObj.startedAt.toString(); 64 | dataObj.updatedAt = dataObj.updatedAt.toString(); 65 | dataObj.answer = dataObj.answer.toString(); 66 | dataObj.answer = parseFloat(dataObj.answer.toString() / 10 ** 8).toFixed(2); 67 | if(debug) console.log('dataObj -- ', coin, dataObj); 68 | return dataObj; 69 | } 70 | 71 | console.log('start --'); 72 | getPriceFeed('eth', chainLinkETHUSD, true); 73 | getPriceFeed('btc', chainLinkBTCUSD, true); 74 | getPriceFeed('bch', chainLinkBCHUSD, true); 75 | 76 | getPriceFeed('dai', chainLinkDAIUSD, true); 77 | getPriceFeed('usdt', chainLinkUSDTUSD, true); 78 | getPriceFeed('usdc', chainLinkUSDCUSD, true); 79 | getPriceFeed('busd', chainLinkBUSDUSD, true); 80 | 81 | getPriceFeed('link', chainLinkLINKUSD, true); 82 | getPriceFeed('uni', chainLinkUNIUSD, true); 83 | getPriceFeed('sushi', chainLinkSUSHIUSD, true); 84 | getPriceFeed('aave', chainLinkAAVEUSD, true); 85 | getPriceFeed('snx', chainLinkSNXUSD, true); 86 | 87 | // getPriceFeed('bnb', chainLinkBNBUSD, true); 88 | 89 | module.exports = { 90 | getPriceFeed 91 | } 92 | return; 93 | 94 | // data eth -- [ 95 | // BigNumber { _hex: '0x05000000000000332f', _isBigNumber: true }, 96 | // BigNumber { _hex: '0x65b9377322', _isBigNumber: true }, 97 | // BigNumber { _hex: '0x617b5491', _isBigNumber: true }, 98 | // BigNumber { _hex: '0x617b5491', _isBigNumber: true }, 99 | // BigNumber { _hex: '0x05000000000000332f', _isBigNumber: true }, 100 | // roundId: BigNumber { _hex: '0x05000000000000332f', _isBigNumber: true }, 101 | // answer: BigNumber { _hex: '0x65b9377322', _isBigNumber: true }, 102 | // startedAt: BigNumber { _hex: '0x617b5491', _isBigNumber: true }, 103 | // updatedAt: BigNumber { _hex: '0x617b5491', _isBigNumber: true }, 104 | // answeredInRound: BigNumber { _hex: '0x05000000000000332f', _isBigNumber: true } 105 | // ] 106 | // data btc -- [ 107 | // BigNumber { _hex: '0x0500000000000027ca', _isBigNumber: true }, 108 | // BigNumber { _hex: '0x0598a24644aa', _isBigNumber: true }, 109 | // BigNumber { _hex: '0x617b54a9', _isBigNumber: true }, 110 | // BigNumber { _hex: '0x617b54a9', _isBigNumber: true }, 111 | // BigNumber { _hex: '0x0500000000000027ca', _isBigNumber: true }, 112 | // roundId: BigNumber { _hex: '0x0500000000000027ca', _isBigNumber: true }, 113 | // answer: BigNumber { _hex: '0x0598a24644aa', _isBigNumber: true }, 114 | // startedAt: BigNumber { _hex: '0x617b54a9', _isBigNumber: true }, 115 | // updatedAt: BigNumber { _hex: '0x617b54a9', _isBigNumber: true }, 116 | // answeredInRound: BigNumber { _hex: '0x0500000000000027ca', _isBigNumber: true } 117 | // ] 118 | 119 | // dataObj -- aave { 120 | // roundId: '55340232221128658975', 121 | // answer: '304.90', 122 | // startedAt: '1635739324', 123 | // updatedAt: '1635739324' 124 | // } 125 | // dataObj -- eth { 126 | // roundId: '92233720368547771338', 127 | // answer: '4185.75', 128 | // startedAt: '1635739360', 129 | // updatedAt: '1635739360' 130 | // } 131 | // dataObj -- btc { 132 | // roundId: '92233720368547768385', 133 | // answer: '59919.45', 134 | // startedAt: '1635739400', 135 | // updatedAt: '1635739400' 136 | // } -------------------------------------------------------------------------------- /hardhat/findVulContracts.js: -------------------------------------------------------------------------------- 1 | // findVulContracts 2 | 3 | // EVM disassembler 4 | // https://github.com/Arachnid/evmdis 5 | // https://github.com/crytic/ethersplay 6 | // https://github.com/MrLuit/evm 7 | // https://github.com/crytic/pyevmasm 8 | // https://github.com/tintinweb/ethereum-dasm 9 | 10 | // EVM decompiler 11 | // https://github.com/eveem-org/panoramix 12 | // https://github.com/ConsenSys/mythril 13 | // https://github.com/trailofbits/manticore 14 | // https://github.com/crytic/slither 15 | // https://github.com/crytic/rattle 16 | // https://github.com/tintinweb/ethereum-dasm 17 | // https://github.com/muellerberndt/sabre 18 | // https://github.com/pventuzelo/octopus 19 | 20 | // EVM fuzzer 21 | // https://github.com/crytic/echidna 22 | // https://github.com/palkeo/pakala 23 | 24 | 25 | // examples 26 | // https://github.com/MrLuit/selfdestruct-detect 27 | 28 | // EVM decompiler api 29 | // http://eveem.org/code/0x06012c8cf97bead5deae237070f9587f8e7a266d.json 30 | 31 | // misc 32 | // https://github.com/statechannels/bytecode-debugger 33 | // https://github.com/0xalpharush/evm-disassembler 34 | 35 | // examples 36 | // https://github.com/ConsenSys/mythril 37 | // myth analyze -a 0x41f83F6F25Eb0D3eB9615Ab7BbBf995E7f7fbA4F --infura-id 460f40a260564ac4a4f4b3fffb032dad --execution-timeout 20 -m AccidentallyKillable 38 | // myth analyze -c 608060405260043610603f57600035 --execution-timeout 20 -m AccidentallyKillable 39 | 40 | // https://github.com/crytic/slither 41 | // slither mycontract.sol 42 | 43 | // https://github.com/eveem-org/panoramix 44 | // python3 panoramix.py 0x41f83F6F25Eb0D3eB9615Ab7BbBf995E7f7fbA4F 45 | 46 | // https://github.com/crytic/pyevmasm 47 | // echo -n "608060405260043610603f57600035" | evmasm -d 48 | 49 | // https://github.com/tintinweb/ethereum-dasm 50 | // echo "608060405260043610603f57600035" | python3 -m ethereum_dasm 51 | // python3 -m ethereum_dasm -a 0x41f83F6F25Eb0D3eB9615Ab7BbBf995E7f7fbA4F 52 | // python3 -m ethereum_dasm -a 0x41f83F6F25Eb0D3eB9615Ab7BbBf995E7f7fbA4F -A --no-color 53 | 54 | const path = require('path'); 55 | require('dotenv').config({path:path.resolve('../', '.env')}); 56 | 57 | const fs = require('fs'); 58 | const axios = require('axios'); 59 | const { providers, utils } = require("ethers"); 60 | const { Interface } = require("@ethersproject/abi"); 61 | const { addABI, getABIs } = require("abi-decoder"); 62 | const { EVM } = require("evm"); 63 | const { inspect } = require('util'); 64 | const exec = require('child_process').exec; 65 | const execute = (command, callback) => { 66 | exec(command, function(error, stdout, stderr){ callback(stdout); }); 67 | }; 68 | 69 | const deepLogs = (obj) => { 70 | return inspect(obj, {depth: 5}); 71 | } 72 | 73 | const { INFURA_APIKEY, ARCHIVENODE_APIKEY, ETHERSCAN_APIKEY } = process.env; 74 | const ETHERSCAN_ABI_ENDPOINT = a => `https://api.etherscan.io/api?module=contract&action=getabi&address=${a}&apikey=${ETHERSCAN_APIKEY}`; 75 | 76 | // const ETHEREUM_RPC_URL = `https://mainnet.infura.io/v3/${INFURA_APIKEY}`; 77 | const ETHEREUM_RPC_URL = `https://api.archivenode.io/${ARCHIVENODE_APIKEY}`; 78 | 79 | const provider = new providers.StaticJsonRpcProvider(ETHEREUM_RPC_URL); 80 | // const provider = new providers.JsonRpcProvider(ETHEREUM_RPC_URL); 81 | // const provider = new providers.getDefaultProvider(ETHEREUM_RPC_URL); 82 | 83 | console.log('start --'); 84 | console.log('ETHEREUM_RPC_URL',ETHEREUM_RPC_URL); 85 | 86 | const checkOp = (codes, op) => { 87 | let i = 0; 88 | const cl = codes.length; 89 | for (i = 0; i < cl; i++) { 90 | let st = codes[i].split(':'); 91 | let opcode = st[1] ? st[1].trim() : null; 92 | if(opcode === op) { 93 | return true; 94 | } 95 | } 96 | return false; 97 | } 98 | 99 | const getBlockNumber = async (n, debug) => { 100 | const blockNumber = await provider.getBlockNumber(); 101 | const blocksPerDay = 6600; 102 | LATEST_BLOCK = blockNumber; 103 | START_SCANNED_BLOCK = blockNumber - (n * blocksPerDay); 104 | if(debug) console.log('latest block',blockNumber); 105 | if(debug) console.log('blocks not scanned',START_SCANNED_BLOCK); 106 | readNumOfBlocks(START_SCANNED_BLOCK, 0, PENDING_BLOCK_SCANNED, 2000, true); 107 | return blockNumber; 108 | } 109 | 110 | const getBlock = async (blockNumber, debug) => { 111 | const block = await provider.getBlockWithTransactions(blockNumber); 112 | // if(debug) console.log('block',block); 113 | return block; 114 | } 115 | 116 | const getABI = async (a, debug) => { 117 | 118 | const api_url = ETHERSCAN_ABI_ENDPOINT(a); 119 | // if(debug) console.log('api -- ',api_url); 120 | 121 | const config = { 122 | timeout: 30000, 123 | url: api_url, 124 | method: 'get', 125 | responseType: 'json' 126 | }; 127 | const res = await axios(config); 128 | const data = res.data; 129 | // if(debug) console.log('data -- ',api_url, deepLogs(data) ); 130 | if(debug) { 131 | if(res.status != 200) console.log('res --', deepLogs(data) ); 132 | } 133 | return data; 134 | } 135 | 136 | const readBlock = async (blockNumber, debug) => { 137 | 138 | let contract_trs = []; 139 | if(debug) console.log('block',blockNumber); 140 | 141 | let block = await getBlock(blockNumber); 142 | let txs = block.transactions; 143 | let j=0; 144 | for(j=0;j { 167 | // t.opCodes = resOpCodes.split('\n'); 168 | // t.selfDestruct = checkOp(t.opCodes, "SELFDESTRUCT"); 169 | // if(t.selfDestruct) contract_trs.push(t); 170 | 171 | // if(debug) console.log('contract opCodes',resOpCodes); 172 | // if(debug) console.log('contract address',t.creates); 173 | // }) 174 | 175 | await execute(`myth analyze -c ${t.data} --execution-timeout 150 `, async (res) => { 176 | t.analyze = res; 177 | if(res.length <= 67) return; 178 | 179 | if(debug) console.log('myth analyze contract ',res); 180 | // if(debug) console.log('myth analyze contract ',typeof res, res.length); 181 | if(debug) console.log('contract address',t.creates); 182 | 183 | let cobj = { 184 | "block":t.blockNumber, 185 | "hash": t.hash, 186 | "address": t.creates, 187 | "byteCode": t.data, 188 | // "opCodes": t.opCodes, 189 | // "jumpDestinations": t.jumpDestinations, 190 | // "interpretedCodes": t.interpretedCodes, 191 | // "solCodes": t.interpretedCodes, 192 | // "selfDestruct": t.selfDestruct, 193 | "analyze": t.analyze 194 | 195 | } 196 | let vulContractsArr = await require(`./json/vul-contracts-clones.json`); 197 | vulContractsArr.push(cobj); 198 | // if(debug) console.log('vulContractsArr ',vulContractsArr); 199 | 200 | // save vul contracts 201 | await fs.writeFile(`${__dirname}/json/vul-contracts-clones.json`, JSON.stringify(vulContractsArr), console.error); 202 | 203 | // save vul contract abi 204 | await fs.writeFile(`${__dirname}/json/${t.blockNumber}-${t.creates}-vul.json`, JSON.stringify(t), console.error); 205 | }) 206 | } 207 | } 208 | } 209 | 210 | const readNumOfBlocks = async (blockNumber, inc, num, inter, debug) => { 211 | setTimeout(() => { 212 | inc++; 213 | // if(debug) console.log('blockNumber' ,blockNumber+inc); 214 | blockNumber+inc < blockNumber+num ? readNumOfBlocks(blockNumber, inc, num, inter, debug) : null; 215 | readBlock(blockNumber+inc, true); 216 | },inter); 217 | } 218 | 219 | let LATEST_BLOCK = 0, START_SCANNED_BLOCK = 0, PENDING_BLOCK_SCANNED = 20000; 220 | 221 | getBlockNumber(3, true); 222 | // readNumOfBlocks(14329929-1, 0, 1, 2000, true); 223 | // execute("echo -n 608060405260043610603f57600035 | evmasm -d", (o)=>{ 224 | // console.log(o); 225 | // }) 226 | 227 | module.exports = { 228 | readNumOfBlocks 229 | } 230 | return; 231 | 232 | -------------------------------------------------------------------------------- /foundry/lib/forge-std/README.md: -------------------------------------------------------------------------------- 1 | # Forge Standard Library • [![tests](https://github.com/brockelmore/forge-std/actions/workflows/tests.yml/badge.svg)](https://github.com/brockelmore/forge-std/actions/workflows/tests.yml) 2 | 3 | Forge Standard Library is a collection of helpful contracts for use with [`forge` and `foundry`](https://github.com/foundry-rs/foundry). It leverages `forge`'s cheatcodes to make writing tests easier and faster, while improving the UX of cheatcodes. 4 | 5 | **Learn how to use Forge Std with the [📖 Foundry Book (Forge Std Guide)](https://book.getfoundry.sh/forge/forge-std.html).** 6 | 7 | ## Install 8 | 9 | ```bash 10 | forge install foundry-rs/forge-std 11 | ``` 12 | 13 | ## Contracts 14 | ### stdError 15 | 16 | This is a helper contract for errors and reverts. In `forge`, this contract is particularly helpful for the `expectRevert` cheatcode, as it provides all compiler builtin errors. 17 | 18 | See the contract itself for all error codes. 19 | 20 | #### Example usage 21 | 22 | ```solidity 23 | 24 | import "forge-std/Test.sol"; 25 | 26 | contract TestContract is Test { 27 | ErrorsTest test; 28 | 29 | function setUp() public { 30 | test = new ErrorsTest(); 31 | } 32 | 33 | function testExpectArithmetic() public { 34 | vm.expectRevert(stdError.arithmeticError); 35 | test.arithmeticError(10); 36 | } 37 | } 38 | 39 | contract ErrorsTest { 40 | function arithmeticError(uint256 a) public { 41 | uint256 a = a - 100; 42 | } 43 | } 44 | ``` 45 | 46 | ### stdStorage 47 | 48 | This is a rather large contract due to all of the overloading to make the UX decent. Primarily, it is a wrapper around the `record` and `accesses` cheatcodes. It can *always* find and write the storage slot(s) associated with a particular variable without knowing the storage layout. The one _major_ caveat to this is while a slot can be found for packed storage variables, we can't write to that variable safely. If a user tries to write to a packed slot, the execution throws an error, unless it is uninitialized (`bytes32(0)`). 49 | 50 | This works by recording all `SLOAD`s and `SSTORE`s during a function call. If there is a single slot read or written to, it immediately returns the slot. Otherwise, behind the scenes, we iterate through and check each one (assuming the user passed in a `depth` parameter). If the variable is a struct, you can pass in a `depth` parameter which is basically the field depth. 51 | 52 | I.e.: 53 | ```solidity 54 | struct T { 55 | // depth 0 56 | uint256 a; 57 | // depth 1 58 | uint256 b; 59 | } 60 | ``` 61 | 62 | #### Example usage 63 | 64 | ```solidity 65 | import "forge-std/Test.sol"; 66 | 67 | contract TestContract is Test { 68 | using stdStorage for StdStorage; 69 | 70 | Storage test; 71 | 72 | function setUp() public { 73 | test = new Storage(); 74 | } 75 | 76 | function testFindExists() public { 77 | // Lets say we want to find the slot for the public 78 | // variable `exists`. We just pass in the function selector 79 | // to the `find` command 80 | uint256 slot = stdstore.target(address(test)).sig("exists()").find(); 81 | assertEq(slot, 0); 82 | } 83 | 84 | function testWriteExists() public { 85 | // Lets say we want to write to the slot for the public 86 | // variable `exists`. We just pass in the function selector 87 | // to the `checked_write` command 88 | stdstore.target(address(test)).sig("exists()").checked_write(100); 89 | assertEq(test.exists(), 100); 90 | } 91 | 92 | // It supports arbitrary storage layouts, like assembly based storage locations 93 | function testFindHidden() public { 94 | // `hidden` is a random hash of a bytes, iteration through slots would 95 | // not find it. Our mechanism does 96 | // Also, you can use the selector instead of a string 97 | uint256 slot = stdstore.target(address(test)).sig(test.hidden.selector).find(); 98 | assertEq(slot, uint256(keccak256("my.random.var"))); 99 | } 100 | 101 | // If targeting a mapping, you have to pass in the keys necessary to perform the find 102 | // i.e.: 103 | function testFindMapping() public { 104 | uint256 slot = stdstore 105 | .target(address(test)) 106 | .sig(test.map_addr.selector) 107 | .with_key(address(this)) 108 | .find(); 109 | // in the `Storage` constructor, we wrote that this address' value was 1 in the map 110 | // so when we load the slot, we expect it to be 1 111 | assertEq(uint(vm.load(address(test), bytes32(slot))), 1); 112 | } 113 | 114 | // If the target is a struct, you can specify the field depth: 115 | function testFindStruct() public { 116 | // NOTE: see the depth parameter - 0 means 0th field, 1 means 1st field, etc. 117 | uint256 slot_for_a_field = stdstore 118 | .target(address(test)) 119 | .sig(test.basicStruct.selector) 120 | .depth(0) 121 | .find(); 122 | 123 | uint256 slot_for_b_field = stdstore 124 | .target(address(test)) 125 | .sig(test.basicStruct.selector) 126 | .depth(1) 127 | .find(); 128 | 129 | assertEq(uint(vm.load(address(test), bytes32(slot_for_a_field))), 1); 130 | assertEq(uint(vm.load(address(test), bytes32(slot_for_b_field))), 2); 131 | } 132 | } 133 | 134 | // A complex storage contract 135 | contract Storage { 136 | struct UnpackedStruct { 137 | uint256 a; 138 | uint256 b; 139 | } 140 | 141 | constructor() { 142 | map_addr[msg.sender] = 1; 143 | } 144 | 145 | uint256 public exists = 1; 146 | mapping(address => uint256) public map_addr; 147 | // mapping(address => Packed) public map_packed; 148 | mapping(address => UnpackedStruct) public map_struct; 149 | mapping(address => mapping(address => uint256)) public deep_map; 150 | mapping(address => mapping(address => UnpackedStruct)) public deep_map_struct; 151 | UnpackedStruct public basicStruct = UnpackedStruct({ 152 | a: 1, 153 | b: 2 154 | }); 155 | 156 | function hidden() public view returns (bytes32 t) { 157 | // an extremely hidden storage slot 158 | bytes32 slot = keccak256("my.random.var"); 159 | assembly { 160 | t := sload(slot) 161 | } 162 | } 163 | } 164 | ``` 165 | 166 | ### stdCheats 167 | 168 | This is a wrapper over miscellaneous cheatcodes that need wrappers to be more dev friendly. Currently there are only functions related to `prank`. In general, users may expect ETH to be put into an address on `prank`, but this is not the case for safety reasons. Explicitly this `hoax` function should only be used for address that have expected balances as it will get overwritten. If an address already has ETH, you should just use `prank`. If you want to change that balance explicitly, just use `deal`. If you want to do both, `hoax` is also right for you. 169 | 170 | 171 | #### Example usage: 172 | ```solidity 173 | 174 | // SPDX-License-Identifier: Unlicense 175 | pragma solidity ^0.8.0; 176 | 177 | import "forge-std/Test.sol"; 178 | 179 | // Inherit the stdCheats 180 | contract StdCheatsTest is Test { 181 | Bar test; 182 | function setUp() public { 183 | test = new Bar(); 184 | } 185 | 186 | function testHoax() public { 187 | // we call `hoax`, which gives the target address 188 | // eth and then calls `prank` 189 | hoax(address(1337)); 190 | test.bar{value: 100}(address(1337)); 191 | 192 | // overloaded to allow you to specify how much eth to 193 | // initialize the address with 194 | hoax(address(1337), 1); 195 | test.bar{value: 1}(address(1337)); 196 | } 197 | 198 | function testStartHoax() public { 199 | // we call `startHoax`, which gives the target address 200 | // eth and then calls `startPrank` 201 | // 202 | // it is also overloaded so that you can specify an eth amount 203 | startHoax(address(1337)); 204 | test.bar{value: 100}(address(1337)); 205 | test.bar{value: 100}(address(1337)); 206 | vm.stopPrank(); 207 | test.bar(address(this)); 208 | } 209 | } 210 | 211 | contract Bar { 212 | function bar(address expectedSender) public payable { 213 | require(msg.sender == expectedSender, "!prank"); 214 | } 215 | } 216 | ``` 217 | 218 | ### Std Assertions 219 | 220 | Expand upon the assertion functions from the `DSTest` library. 221 | 222 | ### `console.log` 223 | 224 | Usage follows the same format as [Hardhat](https://hardhat.org/hardhat-network/reference/#console-log). 225 | It's recommended to use `console2.sol` as shown below, as this will show the decoded logs in Forge traces. 226 | 227 | ```solidity 228 | // import it indirectly via Test.sol 229 | import "forge-std/Test.sol"; 230 | // or directly import it 231 | import "forge-std/console2.sol"; 232 | ... 233 | console2.log(someValue); 234 | ``` 235 | 236 | If you need compatibility with Hardhat, you must use the standard `console.sol` instead. 237 | Due to a bug in `console.sol`, logs that use `uint256` or `int256` types will not be properly decoded in Forge traces. 238 | 239 | ```solidity 240 | // import it indirectly via Test.sol 241 | import "forge-std/Test.sol"; 242 | // or directly import it 243 | import "forge-std/console.sol"; 244 | ... 245 | console.log(someValue); 246 | ``` 247 | -------------------------------------------------------------------------------- /foundry/lib/forge-std/src/test/StdMath.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Unlicense 2 | pragma solidity 0.8.10; 3 | 4 | import "../Test.sol"; 5 | 6 | contract StdMathTest is Test 7 | { 8 | function testGetAbs() external { 9 | assertEq(stdMath.abs(-50), 50); 10 | assertEq(stdMath.abs(50), 50); 11 | assertEq(stdMath.abs(-1337), 1337); 12 | assertEq(stdMath.abs(0), 0); 13 | 14 | assertEq(stdMath.abs(type(int256).min), (type(uint256).max >> 1) + 1); 15 | assertEq(stdMath.abs(type(int256).max), (type(uint256).max >> 1)); 16 | } 17 | 18 | function testGetAbs_Fuzz(int256 a) external { 19 | uint256 manualAbs = getAbs(a); 20 | 21 | uint256 abs = stdMath.abs(a); 22 | 23 | assertEq(abs, manualAbs); 24 | } 25 | 26 | function testGetDelta_Uint() external { 27 | assertEq(stdMath.delta(uint256(0), uint256(0)), 0); 28 | assertEq(stdMath.delta(uint256(0), uint256(1337)), 1337); 29 | assertEq(stdMath.delta(uint256(0), type(uint64).max), type(uint64).max); 30 | assertEq(stdMath.delta(uint256(0), type(uint128).max), type(uint128).max); 31 | assertEq(stdMath.delta(uint256(0), type(uint256).max), type(uint256).max); 32 | 33 | assertEq(stdMath.delta(0, uint256(0)), 0); 34 | assertEq(stdMath.delta(1337, uint256(0)), 1337); 35 | assertEq(stdMath.delta(type(uint64).max, uint256(0)), type(uint64).max); 36 | assertEq(stdMath.delta(type(uint128).max, uint256(0)), type(uint128).max); 37 | assertEq(stdMath.delta(type(uint256).max, uint256(0)), type(uint256).max); 38 | 39 | assertEq(stdMath.delta(1337, uint256(1337)), 0); 40 | assertEq(stdMath.delta(type(uint256).max, type(uint256).max), 0); 41 | assertEq(stdMath.delta(5000, uint256(1250)), 3750); 42 | } 43 | 44 | function testGetDelta_Uint_Fuzz(uint256 a, uint256 b) external { 45 | uint256 manualDelta; 46 | if (a > b) { 47 | manualDelta = a - b; 48 | } else { 49 | manualDelta = b - a; 50 | } 51 | 52 | uint256 delta = stdMath.delta(a, b); 53 | 54 | assertEq(delta, manualDelta); 55 | } 56 | 57 | function testGetDelta_Int() external { 58 | assertEq(stdMath.delta(int256(0), int256(0)), 0); 59 | assertEq(stdMath.delta(int256(0), int256(1337)), 1337); 60 | assertEq(stdMath.delta(int256(0), type(int64).max), type(uint64).max >> 1); 61 | assertEq(stdMath.delta(int256(0), type(int128).max), type(uint128).max >> 1); 62 | assertEq(stdMath.delta(int256(0), type(int256).max), type(uint256).max >> 1); 63 | 64 | assertEq(stdMath.delta(0, int256(0)), 0); 65 | assertEq(stdMath.delta(1337, int256(0)), 1337); 66 | assertEq(stdMath.delta(type(int64).max, int256(0)), type(uint64).max >> 1); 67 | assertEq(stdMath.delta(type(int128).max, int256(0)), type(uint128).max >> 1); 68 | assertEq(stdMath.delta(type(int256).max, int256(0)), type(uint256).max >> 1); 69 | 70 | assertEq(stdMath.delta(-0, int256(0)), 0); 71 | assertEq(stdMath.delta(-1337, int256(0)), 1337); 72 | assertEq(stdMath.delta(type(int64).min, int256(0)), (type(uint64).max >> 1) + 1); 73 | assertEq(stdMath.delta(type(int128).min, int256(0)), (type(uint128).max >> 1) + 1); 74 | assertEq(stdMath.delta(type(int256).min, int256(0)), (type(uint256).max >> 1) + 1); 75 | 76 | assertEq(stdMath.delta(int256(0), -0), 0); 77 | assertEq(stdMath.delta(int256(0), -1337), 1337); 78 | assertEq(stdMath.delta(int256(0), type(int64).min), (type(uint64).max >> 1) + 1); 79 | assertEq(stdMath.delta(int256(0), type(int128).min), (type(uint128).max >> 1) + 1); 80 | assertEq(stdMath.delta(int256(0), type(int256).min), (type(uint256).max >> 1) + 1); 81 | 82 | assertEq(stdMath.delta(1337, int256(1337)), 0); 83 | assertEq(stdMath.delta(type(int256).max, type(int256).max), 0); 84 | assertEq(stdMath.delta(type(int256).min, type(int256).min), 0); 85 | assertEq(stdMath.delta(type(int256).min, type(int256).max), type(uint256).max); 86 | assertEq(stdMath.delta(5000, int256(1250)), 3750); 87 | } 88 | 89 | function testGetDelta_Int_Fuzz(int256 a, int256 b) external { 90 | uint256 absA = getAbs(a); 91 | uint256 absB = getAbs(b); 92 | uint256 absDelta = absA > absB 93 | ? absA - absB 94 | : absB - absA; 95 | 96 | uint256 manualDelta; 97 | if ((a >= 0 && b >= 0) || (a < 0 && b < 0)) { 98 | manualDelta = absDelta; 99 | } 100 | // (a < 0 && b >= 0) || (a >= 0 && b < 0) 101 | else { 102 | manualDelta = absA + absB; 103 | } 104 | 105 | uint256 delta = stdMath.delta(a, b); 106 | 107 | assertEq(delta, manualDelta); 108 | } 109 | 110 | function testGetPercentDelta_Uint() external { 111 | assertEq(stdMath.percentDelta(uint256(0), uint256(1337)), 1e18); 112 | assertEq(stdMath.percentDelta(uint256(0), type(uint64).max), 1e18); 113 | assertEq(stdMath.percentDelta(uint256(0), type(uint128).max), 1e18); 114 | assertEq(stdMath.percentDelta(uint256(0), type(uint192).max), 1e18); 115 | 116 | assertEq(stdMath.percentDelta(1337, uint256(1337)), 0); 117 | assertEq(stdMath.percentDelta(type(uint192).max, type(uint192).max), 0); 118 | assertEq(stdMath.percentDelta(0, uint256(2500)), 1e18); 119 | assertEq(stdMath.percentDelta(2500, uint256(2500)), 0); 120 | assertEq(stdMath.percentDelta(5000, uint256(2500)), 1e18); 121 | assertEq(stdMath.percentDelta(7500, uint256(2500)), 2e18); 122 | 123 | vm.expectRevert(stdError.divisionError); 124 | stdMath.percentDelta(uint256(1), 0); 125 | } 126 | 127 | function testGetPercentDelta_Uint_Fuzz(uint192 a, uint192 b) external { 128 | vm.assume(b != 0); 129 | uint256 manualDelta; 130 | if (a > b) { 131 | manualDelta = a - b; 132 | } else { 133 | manualDelta = b - a; 134 | } 135 | 136 | uint256 manualPercentDelta = manualDelta * 1e18 / b; 137 | uint256 percentDelta = stdMath.percentDelta(a, b); 138 | 139 | assertEq(percentDelta, manualPercentDelta); 140 | } 141 | 142 | function testGetPercentDelta_Int() external { 143 | assertEq(stdMath.percentDelta(int256(0), int256(1337)), 1e18); 144 | assertEq(stdMath.percentDelta(int256(0), -1337), 1e18); 145 | assertEq(stdMath.percentDelta(int256(0), type(int64).min), 1e18); 146 | assertEq(stdMath.percentDelta(int256(0), type(int128).min), 1e18); 147 | assertEq(stdMath.percentDelta(int256(0), type(int192).min), 1e18); 148 | assertEq(stdMath.percentDelta(int256(0), type(int64).max), 1e18); 149 | assertEq(stdMath.percentDelta(int256(0), type(int128).max), 1e18); 150 | assertEq(stdMath.percentDelta(int256(0), type(int192).max), 1e18); 151 | 152 | assertEq(stdMath.percentDelta(1337, int256(1337)), 0); 153 | assertEq(stdMath.percentDelta(type(int192).max, type(int192).max), 0); 154 | assertEq(stdMath.percentDelta(type(int192).min, type(int192).min), 0); 155 | 156 | assertEq(stdMath.percentDelta(type(int192).min, type(int192).max), 2e18); // rounds the 1 wei diff down 157 | assertEq(stdMath.percentDelta(type(int192).max, type(int192).min), 2e18 - 1); // rounds the 1 wei diff down 158 | assertEq(stdMath.percentDelta(0, int256(2500)), 1e18); 159 | assertEq(stdMath.percentDelta(2500, int256(2500)), 0); 160 | assertEq(stdMath.percentDelta(5000, int256(2500)), 1e18); 161 | assertEq(stdMath.percentDelta(7500, int256(2500)), 2e18); 162 | 163 | vm.expectRevert(stdError.divisionError); 164 | stdMath.percentDelta(int256(1), 0); 165 | } 166 | 167 | function testGetPercentDelta_Int_Fuzz(int192 a, int192 b) external { 168 | vm.assume(b != 0); 169 | uint256 absA = getAbs(a); 170 | uint256 absB = getAbs(b); 171 | uint256 absDelta = absA > absB 172 | ? absA - absB 173 | : absB - absA; 174 | 175 | uint256 manualDelta; 176 | if ((a >= 0 && b >= 0) || (a < 0 && b < 0)) { 177 | manualDelta = absDelta; 178 | } 179 | // (a < 0 && b >= 0) || (a >= 0 && b < 0) 180 | else { 181 | manualDelta = absA + absB; 182 | } 183 | 184 | uint256 manualPercentDelta = manualDelta * 1e18 / absB; 185 | uint256 percentDelta = stdMath.percentDelta(a, b); 186 | 187 | assertEq(percentDelta, manualPercentDelta); 188 | } 189 | 190 | /*////////////////////////////////////////////////////////////////////////// 191 | HELPERS 192 | //////////////////////////////////////////////////////////////////////////*/ 193 | 194 | function getAbs(int256 a) private pure returns (uint256) { 195 | if (a < 0) 196 | return a == type(int256).min ? uint256(type(int256).max) + 1 : uint256(-a); 197 | 198 | return uint256(a); 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /findFlashLoanTxs.js: -------------------------------------------------------------------------------- 1 | // findFlashLoanTxs 2 | require('dotenv').config(); 3 | const fs = require('fs'); 4 | const axios = require('axios'); 5 | const { providers, utils } = require("ethers"); 6 | const { addABI, getABIs, decodeMethod } = require("abi-decoder"); 7 | const { inspect } = require('util'); 8 | 9 | const deepLogs = (obj) => { 10 | return inspect(obj, {depth: 5}); 11 | } 12 | 13 | const findMatches = (clone, org, debug) => { 14 | const clone_filter = clone.filter( a => { 15 | return a.type == 'function' ? true : false; 16 | }) 17 | const org_filter = org.filter( b => { 18 | return b.type == 'function' ? true : false; 19 | }) 20 | // if(debug) console.log('abi fn filter',clone_filter, org_filter); 21 | 22 | const finds = org_filter.filter( j => { 23 | return clone_filter.some( k => { 24 | // if(debug) console.log('j.name == k.name', j.name, k.name); 25 | return j.name == k.name ? true : false; 26 | }); 27 | }); 28 | // if(debug) console.log('finds',finds); 29 | return finds; 30 | } 31 | const arrayUnique = (array) => { 32 | var a = array.concat(); 33 | for(var i=0; i `https://api.etherscan.io/api?module=contract&action=getabi&address=${a}&apikey=${ETHERSCAN_APIKEY}`; 168 | 169 | // const ETHEREUM_RPC_URL = `https://mainnet.infura.io/v3/${INFURA_APIKEY}`; 170 | const ETHEREUM_RPC_URL = `https://api.archivenode.io/${ARCHIVENODE_APIKEY}`; 171 | 172 | const provider = new providers.StaticJsonRpcProvider(ETHEREUM_RPC_URL); 173 | // const provider = new providers.JsonRpcProvider(ETHEREUM_RPC_URL); 174 | // const provider = new providers.getDefaultProvider(ETHEREUM_RPC_URL); 175 | 176 | console.log('start --'); 177 | console.log('ETHEREUM_RPC_URL',ETHEREUM_RPC_URL); 178 | 179 | const getBlockNumber = async (n, debug) => { 180 | const blockNumber = await provider.getBlockNumber(); 181 | const blocksPerDay = 6600; 182 | LATEST_BLOCK = blockNumber; 183 | START_SCANNED_BLOCK = blockNumber - (n * blocksPerDay); 184 | if(debug) console.log('latest block',blockNumber); 185 | if(debug) console.log('blocks not scanned',START_SCANNED_BLOCK); 186 | readNumOfBlocks(START_SCANNED_BLOCK, 0, PENDING_BLOCK_SCANNED, 3000, true); 187 | return blockNumber; 188 | } 189 | 190 | const getBlock = async (blockNumber, debug) => { 191 | const block = await provider.getBlockWithTransactions(blockNumber); 192 | // if(debug) console.log('block',block); 193 | return block; 194 | } 195 | const getTxRc = async (hash, debug) => { 196 | const tx = await provider.getTransactionReceipt(hash); 197 | if(debug) console.log('tx',tx); 198 | return tx; 199 | } 200 | 201 | const getABI = async (a, debug) => { 202 | 203 | const api_url = ETHERSCAN_ABI_ENDPOINT(a); 204 | // if(debug) console.log('api -- ',api_url); 205 | 206 | const config = { 207 | timeout: 30000, 208 | url: api_url, 209 | method: 'get', 210 | responseType: 'json' 211 | }; 212 | const res = await axios(config); 213 | const data = res.data; 214 | // if(debug) console.log('data -- ',api_url, deepLogs(data) ); 215 | if(debug) { 216 | if(res.status != 200) console.log('res --', deepLogs(data) ); 217 | } 218 | return data; 219 | } 220 | 221 | const readBlock = async (blockNumber, debug) => { 222 | 223 | let contract_trs = []; 224 | 225 | if(debug) console.log('block',blockNumber); 226 | 227 | let block = await getBlock(blockNumber); 228 | let txs = block.transactions; 229 | let j=0; 230 | for(j=0;j 0){ 247 | contract_trs.map( async c => { 248 | let cobj = { 249 | "block":c.blockNumber, 250 | "hash": c.hash, 251 | "address": c.to, 252 | "input": c.decodeMethod 253 | } 254 | let clonesArr = await require(`./json/flashloan-trxs-clones.json`); 255 | clonesArr.push(cobj); 256 | // if(debug) console.log('clonesArr ',clonesArr); 257 | await fs.writeFile(`${__dirname}/json/flashloan-trxs-clones.json`, JSON.stringify(clonesArr), console.error); 258 | }) 259 | } 260 | } 261 | 262 | const readNumOfBlocks = async (blockNumber, inc, num, inter, debug) => { 263 | setTimeout(() => { 264 | inc++; 265 | // if(debug) console.log('blockNumber' ,blockNumber+inc); 266 | blockNumber+inc < blockNumber+num ? readNumOfBlocks(blockNumber, inc, num, inter, debug) : null; 267 | readBlock(blockNumber+inc, true); 268 | },inter); 269 | } 270 | 271 | let LATEST_BLOCK = 0, START_SCANNED_BLOCK = 0, PENDING_BLOCK_SCANNED = 10000; 272 | 273 | // getBlockNumber(1, true); 274 | // readNumOfBlocks(14241915-1, 0, 1, 2000, true); 275 | 276 | // scanned uniswap v2 flashswap 277 | // "block": 14092755, 278 | // "hash": "0x284101ec1389344b360d10caa9a5c8be8fc75fe87c0a3273a0716539b5357ffd", 279 | // "address": "0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc", 280 | 281 | module.exports = { 282 | readNumOfBlocks 283 | } 284 | return; 285 | 286 | -------------------------------------------------------------------------------- /foundry/lib/forge-std/src/test/StdStorage.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Unlicense 2 | pragma solidity >=0.6.0 <0.9.0; 3 | 4 | import "../Test.sol"; 5 | 6 | contract StdStorageTest is Test { 7 | using stdStorage for StdStorage; 8 | 9 | StorageTest test; 10 | 11 | function setUp() public { 12 | test = new StorageTest(); 13 | } 14 | 15 | function testStorageHidden() public { 16 | assertEq(uint256(keccak256("my.random.var")), stdstore.target(address(test)).sig("hidden()").find()); 17 | } 18 | 19 | function testStorageObvious() public { 20 | assertEq(uint256(0), stdstore.target(address(test)).sig("exists()").find()); 21 | } 22 | 23 | function testStorageCheckedWriteHidden() public { 24 | stdstore.target(address(test)).sig(test.hidden.selector).checked_write(100); 25 | assertEq(uint256(test.hidden()), 100); 26 | } 27 | 28 | function testStorageCheckedWriteObvious() public { 29 | stdstore.target(address(test)).sig(test.exists.selector).checked_write(100); 30 | assertEq(test.exists(), 100); 31 | } 32 | 33 | function testStorageMapStructA() public { 34 | uint256 slot = stdstore 35 | .target(address(test)) 36 | .sig(test.map_struct.selector) 37 | .with_key(address(this)) 38 | .depth(0) 39 | .find(); 40 | assertEq(uint256(keccak256(abi.encode(address(this), 4))), slot); 41 | } 42 | 43 | function testStorageMapStructB() public { 44 | uint256 slot = stdstore 45 | .target(address(test)) 46 | .sig(test.map_struct.selector) 47 | .with_key(address(this)) 48 | .depth(1) 49 | .find(); 50 | assertEq(uint256(keccak256(abi.encode(address(this), 4))) + 1, slot); 51 | } 52 | 53 | function testStorageDeepMap() public { 54 | uint256 slot = stdstore 55 | .target(address(test)) 56 | .sig(test.deep_map.selector) 57 | .with_key(address(this)) 58 | .with_key(address(this)) 59 | .find(); 60 | assertEq(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint(5)))))), slot); 61 | } 62 | 63 | function testStorageCheckedWriteDeepMap() public { 64 | stdstore 65 | .target(address(test)) 66 | .sig(test.deep_map.selector) 67 | .with_key(address(this)) 68 | .with_key(address(this)) 69 | .checked_write(100); 70 | assertEq(100, test.deep_map(address(this), address(this))); 71 | } 72 | 73 | function testStorageDeepMapStructA() public { 74 | uint256 slot = stdstore 75 | .target(address(test)) 76 | .sig(test.deep_map_struct.selector) 77 | .with_key(address(this)) 78 | .with_key(address(this)) 79 | .depth(0) 80 | .find(); 81 | assertEq(bytes32(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint(6)))))) + 0), bytes32(slot)); 82 | } 83 | 84 | function testStorageDeepMapStructB() public { 85 | uint256 slot = stdstore 86 | .target(address(test)) 87 | .sig(test.deep_map_struct.selector) 88 | .with_key(address(this)) 89 | .with_key(address(this)) 90 | .depth(1) 91 | .find(); 92 | assertEq(bytes32(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint(6)))))) + 1), bytes32(slot)); 93 | } 94 | 95 | function testStorageCheckedWriteDeepMapStructA() public { 96 | stdstore 97 | .target(address(test)) 98 | .sig(test.deep_map_struct.selector) 99 | .with_key(address(this)) 100 | .with_key(address(this)) 101 | .depth(0) 102 | .checked_write(100); 103 | (uint256 a, uint256 b) = test.deep_map_struct(address(this), address(this)); 104 | assertEq(100, a); 105 | assertEq(0, b); 106 | } 107 | 108 | function testStorageCheckedWriteDeepMapStructB() public { 109 | stdstore 110 | .target(address(test)) 111 | .sig(test.deep_map_struct.selector) 112 | .with_key(address(this)) 113 | .with_key(address(this)) 114 | .depth(1) 115 | .checked_write(100); 116 | (uint256 a, uint256 b) = test.deep_map_struct(address(this), address(this)); 117 | assertEq(0, a); 118 | assertEq(100, b); 119 | } 120 | 121 | function testStorageCheckedWriteMapStructA() public { 122 | stdstore 123 | .target(address(test)) 124 | .sig(test.map_struct.selector) 125 | .with_key(address(this)) 126 | .depth(0) 127 | .checked_write(100); 128 | (uint256 a, uint256 b) = test.map_struct(address(this)); 129 | assertEq(a, 100); 130 | assertEq(b, 0); 131 | } 132 | 133 | function testStorageCheckedWriteMapStructB() public { 134 | stdstore 135 | .target(address(test)) 136 | .sig(test.map_struct.selector) 137 | .with_key(address(this)) 138 | .depth(1) 139 | .checked_write(100); 140 | (uint256 a, uint256 b) = test.map_struct(address(this)); 141 | assertEq(a, 0); 142 | assertEq(b, 100); 143 | } 144 | 145 | function testStorageStructA() public { 146 | uint256 slot = stdstore.target(address(test)).sig(test.basic.selector).depth(0).find(); 147 | assertEq(uint256(7), slot); 148 | } 149 | 150 | function testStorageStructB() public { 151 | uint256 slot = stdstore.target(address(test)).sig(test.basic.selector).depth(1).find(); 152 | assertEq(uint256(7) + 1, slot); 153 | } 154 | 155 | function testStorageCheckedWriteStructA() public { 156 | stdstore.target(address(test)).sig(test.basic.selector).depth(0).checked_write(100); 157 | (uint256 a, uint256 b) = test.basic(); 158 | assertEq(a, 100); 159 | assertEq(b, 1337); 160 | } 161 | 162 | function testStorageCheckedWriteStructB() public { 163 | stdstore.target(address(test)).sig(test.basic.selector).depth(1).checked_write(100); 164 | (uint256 a, uint256 b) = test.basic(); 165 | assertEq(a, 1337); 166 | assertEq(b, 100); 167 | } 168 | 169 | function testStorageMapAddrFound() public { 170 | uint256 slot = stdstore.target(address(test)).sig(test.map_addr.selector).with_key(address(this)).find(); 171 | assertEq(uint256(keccak256(abi.encode(address(this), uint(1)))), slot); 172 | } 173 | 174 | function testStorageMapUintFound() public { 175 | uint256 slot = stdstore.target(address(test)).sig(test.map_uint.selector).with_key(100).find(); 176 | assertEq(uint256(keccak256(abi.encode(100, uint(2)))), slot); 177 | } 178 | 179 | function testStorageCheckedWriteMapUint() public { 180 | stdstore.target(address(test)).sig(test.map_uint.selector).with_key(100).checked_write(100); 181 | assertEq(100, test.map_uint(100)); 182 | } 183 | 184 | function testStorageCheckedWriteMapAddr() public { 185 | stdstore.target(address(test)).sig(test.map_addr.selector).with_key(address(this)).checked_write(100); 186 | assertEq(100, test.map_addr(address(this))); 187 | } 188 | 189 | function testStorageCheckedWriteMapBool() public { 190 | stdstore.target(address(test)).sig(test.map_bool.selector).with_key(address(this)).checked_write(true); 191 | assertTrue(test.map_bool(address(this))); 192 | } 193 | 194 | function testFailStorageCheckedWriteMapPacked() public { 195 | // expect PackedSlot error but not external call so cant expectRevert 196 | stdstore.target(address(test)).sig(test.read_struct_lower.selector).with_key(address(uint160(1337))).checked_write(100); 197 | } 198 | 199 | function testStorageCheckedWriteMapPackedSuccess() public { 200 | uint256 full = test.map_packed(address(1337)); 201 | // keep upper 128, set lower 128 to 1337 202 | full = (full & (uint256((1 << 128) - 1) << 128)) | 1337; 203 | stdstore.target(address(test)).sig(test.map_packed.selector).with_key(address(uint160(1337))).checked_write(full); 204 | assertEq(1337, test.read_struct_lower(address(1337))); 205 | } 206 | 207 | function testFailStorageConst() public { 208 | // vm.expectRevert(abi.encodeWithSignature("NotStorage(bytes4)", bytes4(keccak256("const()")))); 209 | stdstore.target(address(test)).sig("const()").find(); 210 | } 211 | 212 | function testFailStorageNativePack() public { 213 | stdstore.target(address(test)).sig(test.tA.selector).find(); 214 | stdstore.target(address(test)).sig(test.tB.selector).find(); 215 | 216 | // these both would fail 217 | stdstore.target(address(test)).sig(test.tC.selector).find(); 218 | stdstore.target(address(test)).sig(test.tD.selector).find(); 219 | } 220 | } 221 | 222 | contract StorageTest { 223 | uint256 public exists = 1; 224 | mapping(address => uint256) public map_addr; 225 | mapping(uint256 => uint256) public map_uint; 226 | mapping(address => uint256) public map_packed; 227 | mapping(address => UnpackedStruct) public map_struct; 228 | mapping(address => mapping(address => uint256)) public deep_map; 229 | mapping(address => mapping(address => UnpackedStruct)) public deep_map_struct; 230 | UnpackedStruct public basic; 231 | 232 | uint248 public tA; 233 | bool public tB; 234 | 235 | 236 | bool public tC = false; 237 | uint248 public tD = 1; 238 | 239 | 240 | struct UnpackedStruct { 241 | uint256 a; 242 | uint256 b; 243 | } 244 | 245 | mapping(address => bool) public map_bool; 246 | 247 | constructor() { 248 | basic = UnpackedStruct({ 249 | a: 1337, 250 | b: 1337 251 | }); 252 | 253 | uint256 two = (1<<128) | 1; 254 | map_packed[msg.sender] = two; 255 | map_packed[address(bytes20(uint160(1337)))] = 1<<128; 256 | } 257 | 258 | function read_struct_upper(address who) public view returns (uint256) { 259 | return map_packed[who] >> 128; 260 | } 261 | 262 | function read_struct_lower(address who) public view returns (uint256) { 263 | return map_packed[who] & ((1 << 128) - 1); 264 | } 265 | 266 | function hidden() public view returns (bytes32 t) { 267 | bytes32 slot = keccak256("my.random.var"); 268 | /// @solidity memory-safe-assembly 269 | assembly { 270 | t := sload(slot) 271 | } 272 | } 273 | 274 | function const() public pure returns (bytes32 t) { 275 | t = bytes32(hex"1337"); 276 | } 277 | } 278 | -------------------------------------------------------------------------------- /foundry/lib/forge-std/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021 Brock Elmore 2 | 3 | Apache License 4 | Version 2.0, January 2004 5 | http://www.apache.org/licenses/ 6 | 7 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 8 | 9 | 1. Definitions. 10 | 11 | "License" shall mean the terms and conditions for use, reproduction, 12 | and distribution as defined by Sections 1 through 9 of this document. 13 | 14 | "Licensor" shall mean the copyright owner or entity authorized by 15 | the copyright owner that is granting the License. 16 | 17 | "Legal Entity" shall mean the union of the acting entity and all 18 | other entities that control, are controlled by, or are under common 19 | control with that entity. For the purposes of this definition, 20 | "control" means (i) the power, direct or indirect, to cause the 21 | direction or management of such entity, whether by contract or 22 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 23 | outstanding shares, or (iii) beneficial ownership of such entity. 24 | 25 | "You" (or "Your") shall mean an individual or Legal Entity 26 | exercising permissions granted by this License. 27 | 28 | "Source" form shall mean the preferred form for making modifications, 29 | including but not limited to software source code, documentation 30 | source, and configuration files. 31 | 32 | "Object" form shall mean any form resulting from mechanical 33 | transformation or translation of a Source form, including but 34 | not limited to compiled object code, generated documentation, 35 | and conversions to other media types. 36 | 37 | "Work" shall mean the work of authorship, whether in Source or 38 | Object form, made available under the License, as indicated by a 39 | copyright notice that is included in or attached to the work 40 | (an example is provided in the Appendix below). 41 | 42 | "Derivative Works" shall mean any work, whether in Source or Object 43 | form, that is based on (or derived from) the Work and for which the 44 | editorial revisions, annotations, elaborations, or other modifications 45 | represent, as a whole, an original work of authorship. For the purposes 46 | of this License, Derivative Works shall not include works that remain 47 | separable from, or merely link (or bind by name) to the interfaces of, 48 | the Work and Derivative Works thereof. 49 | 50 | "Contribution" shall mean any work of authorship, including 51 | the original version of the Work and any modifications or additions 52 | to that Work or Derivative Works thereof, that is intentionally 53 | submitted to Licensor for inclusion in the Work by the copyright owner 54 | or by an individual or Legal Entity authorized to submit on behalf of 55 | the copyright owner. For the purposes of this definition, "submitted" 56 | means any form of electronic, verbal, or written communication sent 57 | to the Licensor or its representatives, including but not limited to 58 | communication on electronic mailing lists, source code control systems, 59 | and issue tracking systems that are managed by, or on behalf of, the 60 | Licensor for the purpose of discussing and improving the Work, but 61 | excluding communication that is conspicuously marked or otherwise 62 | designated in writing by the copyright owner as "Not a Contribution." 63 | 64 | "Contributor" shall mean Licensor and any individual or Legal Entity 65 | on behalf of whom a Contribution has been received by Licensor and 66 | subsequently incorporated within the Work. 67 | 68 | 2. Grant of Copyright License. Subject to the terms and conditions of 69 | this License, each Contributor hereby grants to You a perpetual, 70 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 71 | copyright license to reproduce, prepare Derivative Works of, 72 | publicly display, publicly perform, sublicense, and distribute the 73 | Work and such Derivative Works in Source or Object form. 74 | 75 | 3. Grant of Patent License. Subject to the terms and conditions of 76 | this License, each Contributor hereby grants to You a perpetual, 77 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 78 | (except as stated in this section) patent license to make, have made, 79 | use, offer to sell, sell, import, and otherwise transfer the Work, 80 | where such license applies only to those patent claims licensable 81 | by such Contributor that are necessarily infringed by their 82 | Contribution(s) alone or by combination of their Contribution(s) 83 | with the Work to which such Contribution(s) was submitted. If You 84 | institute patent litigation against any entity (including a 85 | cross-claim or counterclaim in a lawsuit) alleging that the Work 86 | or a Contribution incorporated within the Work constitutes direct 87 | or contributory patent infringement, then any patent licenses 88 | granted to You under this License for that Work shall terminate 89 | as of the date such litigation is filed. 90 | 91 | 4. Redistribution. You may reproduce and distribute copies of the 92 | Work or Derivative Works thereof in any medium, with or without 93 | modifications, and in Source or Object form, provided that You 94 | meet the following conditions: 95 | 96 | (a) You must give any other recipients of the Work or 97 | Derivative Works a copy of this License; and 98 | 99 | (b) You must cause any modified files to carry prominent notices 100 | stating that You changed the files; and 101 | 102 | (c) You must retain, in the Source form of any Derivative Works 103 | that You distribute, all copyright, patent, trademark, and 104 | attribution notices from the Source form of the Work, 105 | excluding those notices that do not pertain to any part of 106 | the Derivative Works; and 107 | 108 | (d) If the Work includes a "NOTICE" text file as part of its 109 | distribution, then any Derivative Works that You distribute must 110 | include a readable copy of the attribution notices contained 111 | within such NOTICE file, excluding those notices that do not 112 | pertain to any part of the Derivative Works, in at least one 113 | of the following places: within a NOTICE text file distributed 114 | as part of the Derivative Works; within the Source form or 115 | documentation, if provided along with the Derivative Works; or, 116 | within a display generated by the Derivative Works, if and 117 | wherever such third-party notices normally appear. The contents 118 | of the NOTICE file are for informational purposes only and 119 | do not modify the License. You may add Your own attribution 120 | notices within Derivative Works that You distribute, alongside 121 | or as an addendum to the NOTICE text from the Work, provided 122 | that such additional attribution notices cannot be construed 123 | as modifying the License. 124 | 125 | You may add Your own copyright statement to Your modifications and 126 | may provide additional or different license terms and conditions 127 | for use, reproduction, or distribution of Your modifications, or 128 | for any such Derivative Works as a whole, provided Your use, 129 | reproduction, and distribution of the Work otherwise complies with 130 | the conditions stated in this License. 131 | 132 | 5. Submission of Contributions. Unless You explicitly state otherwise, 133 | any Contribution intentionally submitted for inclusion in the Work 134 | by You to the Licensor shall be under the terms and conditions of 135 | this License, without any additional terms or conditions. 136 | Notwithstanding the above, nothing herein shall supersede or modify 137 | the terms of any separate license agreement you may have executed 138 | with Licensor regarding such Contributions. 139 | 140 | 6. Trademarks. This License does not grant permission to use the trade 141 | names, trademarks, service marks, or product names of the Licensor, 142 | except as required for reasonable and customary use in describing the 143 | origin of the Work and reproducing the content of the NOTICE file. 144 | 145 | 7. Disclaimer of Warranty. Unless required by applicable law or 146 | agreed to in writing, Licensor provides the Work (and each 147 | Contributor provides its Contributions) on an "AS IS" BASIS, 148 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 149 | implied, including, without limitation, any warranties or conditions 150 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 151 | PARTICULAR PURPOSE. You are solely responsible for determining the 152 | appropriateness of using or redistributing the Work and assume any 153 | risks associated with Your exercise of permissions under this License. 154 | 155 | 8. Limitation of Liability. In no event and under no legal theory, 156 | whether in tort (including negligence), contract, or otherwise, 157 | unless required by applicable law (such as deliberate and grossly 158 | negligent acts) or agreed to in writing, shall any Contributor be 159 | liable to You for damages, including any direct, indirect, special, 160 | incidental, or consequential damages of any character arising as a 161 | result of this License or out of the use or inability to use the 162 | Work (including but not limited to damages for loss of goodwill, 163 | work stoppage, computer failure or malfunction, or any and all 164 | other commercial damages or losses), even if such Contributor 165 | has been advised of the possibility of such damages. 166 | 167 | 9. Accepting Warranty or Additional Liability. While redistributing 168 | the Work or Derivative Works thereof, You may choose to offer, 169 | and charge a fee for, acceptance of support, warranty, indemnity, 170 | or other liability obligations and/or rights consistent with this 171 | License. However, in accepting such obligations, You may act only 172 | on Your own behalf and on Your sole responsibility, not on behalf 173 | of any other Contributor, and only if You agree to indemnify, 174 | defend, and hold each Contributor harmless for any liability 175 | incurred by, or claims asserted against, such Contributor by reason 176 | of your accepting any such warranty or additional liability. 177 | 178 | END OF TERMS AND CONDITIONS 179 | 180 | APPENDIX: How to apply the Apache License to your work. 181 | 182 | To apply the Apache License to your work, attach the following 183 | boilerplate notice, with the fields enclosed by brackets "[]" 184 | replaced with your own identifying information. (Don't include 185 | the brackets!) The text should be enclosed in the appropriate 186 | comment syntax for the file format. We also recommend that a 187 | file or class name and description of purpose be included on the 188 | same "printed page" as the copyright notice for easier 189 | identification within third-party archives. 190 | 191 | Copyright [yyyy] [name of copyright owner] 192 | 193 | Licensed under the Apache License, Version 2.0 (the "License"); 194 | you may not use this file except in compliance with the License. 195 | You may obtain a copy of the License at 196 | 197 | http://www.apache.org/licenses/LICENSE-2.0 198 | 199 | Unless required by applicable law or agreed to in writing, software 200 | distributed under the License is distributed on an "AS IS" BASIS, 201 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 202 | See the License for the specific language governing permissions and 203 | limitations under the License. 204 | -------------------------------------------------------------------------------- /liquidations/findUniswapV3Txs.js: -------------------------------------------------------------------------------- 1 | // findUniswapV3Txs 2 | const path = require('path'); 3 | require('dotenv').config({path:path.resolve('../', '.env')}); 4 | const fs = require('fs'); 5 | const axios = require('axios'); 6 | const { providers, utils } = require("ethers"); 7 | const { addABI, getABIs, decodeMethod } = require("abi-decoder"); 8 | const { inspect } = require('util'); 9 | 10 | const deepLogs = (obj) => { 11 | return inspect(obj, {depth: 5}); 12 | } 13 | 14 | const findMatches = (clone, org, debug) => { 15 | const clone_filter = clone.filter( a => { 16 | return a.type == 'function' ? true : false; 17 | }) 18 | const org_filter = org.filter( b => { 19 | return b.type == 'function' ? true : false; 20 | }) 21 | // if(debug) console.log('abi fn filter',clone_filter, org_filter); 22 | 23 | const finds = org_filter.filter( j => { 24 | return clone_filter.some( k => { 25 | // if(debug) console.log('j.name == k.name', j.name, k.name); 26 | return j.name == k.name ? true : false; 27 | }); 28 | }); 29 | // if(debug) console.log('finds',finds); 30 | return finds; 31 | } 32 | const arrayUnique = (array) => { 33 | var a = array.concat(); 34 | for(var i=0; i `https://api.etherscan.io/api?module=contract&action=getabi&address=${a}&apikey=${ETHERSCAN_APIKEY}`; 238 | 239 | // const ETHEREUM_RPC_URL = `https://mainnet.infura.io/v3/${INFURA_APIKEY}`; 240 | const ETHEREUM_RPC_URL = `https://api.archivenode.io/${ARCHIVENODE_APIKEY}`; 241 | 242 | const provider = new providers.StaticJsonRpcProvider(ETHEREUM_RPC_URL); 243 | // const provider = new providers.JsonRpcProvider(ETHEREUM_RPC_URL); 244 | // const provider = new providers.getDefaultProvider(ETHEREUM_RPC_URL); 245 | 246 | console.log('start --'); 247 | console.log('ETHEREUM_RPC_URL',ETHEREUM_RPC_URL); 248 | 249 | const getBlockNumber = async (n, debug) => { 250 | const blockNumber = await provider.getBlockNumber(); 251 | const blocksPerDay = 6600; 252 | LATEST_BLOCK = blockNumber; 253 | START_SCANNED_BLOCK = blockNumber - (n * blocksPerDay); 254 | if(debug) console.log('latest block',blockNumber); 255 | if(debug) console.log('blocks not scanned',START_SCANNED_BLOCK); 256 | readNumOfBlocks(START_SCANNED_BLOCK, 0, PENDING_BLOCK_SCANNED, 3000, true); 257 | return blockNumber; 258 | } 259 | 260 | const getBlock = async (blockNumber, debug) => { 261 | const block = await provider.getBlockWithTransactions(blockNumber); 262 | // if(debug) console.log('block',block); 263 | return block; 264 | } 265 | const getTxRc = async (hash, debug) => { 266 | const tx = await provider.getTransactionReceipt(hash); 267 | if(debug) console.log('tx',tx); 268 | return tx; 269 | } 270 | 271 | const getABI = async (a, debug) => { 272 | 273 | const api_url = ETHERSCAN_ABI_ENDPOINT(a); 274 | // if(debug) console.log('api -- ',api_url); 275 | 276 | const config = { 277 | timeout: 30000, 278 | url: api_url, 279 | method: 'get', 280 | responseType: 'json' 281 | }; 282 | const res = await axios(config); 283 | const data = res.data; 284 | // if(debug) console.log('data -- ',api_url, deepLogs(data) ); 285 | if(debug) { 286 | if(res.status != 200) console.log('res --', deepLogs(data) ); 287 | } 288 | return data; 289 | } 290 | 291 | const readBlock = async (blockNumber, debug) => { 292 | 293 | let contract_trs = []; 294 | 295 | if(debug) console.log('block',blockNumber); 296 | 297 | let block = await getBlock(blockNumber); 298 | let txs = block.transactions; 299 | let j=0; 300 | for(j=0;j 0){ 319 | contract_trs.map( async c => { 320 | let cobj = { 321 | "block":c.blockNumber, 322 | "hash": c.hash, 323 | "address": c.to, 324 | "input": c.decodeMethod 325 | } 326 | let clonesArr = await require(`./json/uniswapv3-liquidations-trxs.json`); 327 | clonesArr.push(cobj); 328 | // if(debug) console.log('clonesArr ',clonesArr); 329 | await fs.writeFile(`${__dirname}/json/uniswapv3-liquidations-trxs.json`, JSON.stringify(clonesArr), console.error); 330 | }) 331 | } 332 | } 333 | 334 | const readNumOfBlocks = async (blockNumber, inc, num, inter, debug) => { 335 | setTimeout(() => { 336 | inc++; 337 | // if(debug) console.log('blockNumber' ,blockNumber+inc); 338 | blockNumber+inc < blockNumber+num ? readNumOfBlocks(blockNumber, inc, num, inter, debug) : null; 339 | readBlock(blockNumber+inc, true); 340 | },inter); 341 | } 342 | 343 | let LATEST_BLOCK = 0, START_SCANNED_BLOCK = 0, PENDING_BLOCK_SCANNED = 10000; 344 | 345 | getBlockNumber(1, true); 346 | // readNumOfBlocks(14839482-1, 0, 1, 2000, true); 347 | 348 | // scanned uniswap v2 liquidation trx 349 | // "block": 14839482, 350 | // "hash": "0x7e7d19f4df364b3524dfb7d52eda9b7920078cd7376eba563db9058a900948b0", 351 | // "address": "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D", 352 | 353 | module.exports = { 354 | readNumOfBlocks 355 | } 356 | return; 357 | 358 | -------------------------------------------------------------------------------- /foundry/lib/forge-std/src/test/StdAssertions.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Unlicense 2 | pragma solidity 0.8.10; 3 | 4 | import "../Test.sol"; 5 | 6 | contract StdAssertionsTest is Test 7 | { 8 | string constant CUSTOM_ERROR = "guh!"; 9 | 10 | bool constant EXPECT_PASS = false; 11 | bool constant EXPECT_FAIL = true; 12 | 13 | TestTest t = new TestTest(); 14 | 15 | /*////////////////////////////////////////////////////////////////////////// 16 | ASSERT_FALSE 17 | //////////////////////////////////////////////////////////////////////////*/ 18 | 19 | function testAssertFalse_Pass() external { 20 | t._assertFalse(false, EXPECT_PASS); 21 | } 22 | 23 | function testAssertFalse_Fail() external { 24 | vm.expectEmit(false, false, false, true); 25 | emit log("Error: Assertion Failed"); 26 | t._assertFalse(true, EXPECT_FAIL); 27 | } 28 | 29 | function testAssertFalse_Err_Pass() external { 30 | t._assertFalse(false, CUSTOM_ERROR, EXPECT_PASS); 31 | } 32 | 33 | function testAssertFalse_Err_Fail() external { 34 | vm.expectEmit(true, false, false, true); 35 | emit log_named_string("Error", CUSTOM_ERROR); 36 | t._assertFalse(true, CUSTOM_ERROR, EXPECT_FAIL); 37 | } 38 | 39 | /*////////////////////////////////////////////////////////////////////////// 40 | ASSERT_EQ(BOOL) 41 | //////////////////////////////////////////////////////////////////////////*/ 42 | 43 | function testAssertEq_Bool_Pass(bool a, bool b) external { 44 | vm.assume(a == b); 45 | 46 | t._assertEq(a, b, EXPECT_PASS); 47 | } 48 | 49 | function testAssertEq_Bool_Fail(bool a, bool b) external { 50 | vm.assume(a != b); 51 | 52 | vm.expectEmit(false, false, false, true); 53 | emit log("Error: a == b not satisfied [bool]"); 54 | t._assertEq(a, b, EXPECT_FAIL); 55 | } 56 | 57 | function testAssertEq_BoolErr_Pass(bool a, bool b) external { 58 | vm.assume(a == b); 59 | 60 | t._assertEq(a, b, CUSTOM_ERROR, EXPECT_PASS); 61 | } 62 | 63 | function testAssertEq_BoolErr_Fail(bool a, bool b) external { 64 | vm.assume(a != b); 65 | 66 | vm.expectEmit(true, false, false, true); 67 | emit log_named_string("Error", CUSTOM_ERROR); 68 | t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); 69 | } 70 | 71 | /*////////////////////////////////////////////////////////////////////////// 72 | ASSERT_EQ(BYTES) 73 | //////////////////////////////////////////////////////////////////////////*/ 74 | 75 | function testAssertEq_Bytes_Pass(bytes calldata a, bytes calldata b) external { 76 | vm.assume(keccak256(a) == keccak256(b)); 77 | 78 | t._assertEq(a, b, EXPECT_PASS); 79 | } 80 | 81 | function testAssertEq_Bytes_Fail(bytes calldata a, bytes calldata b) external { 82 | vm.assume(keccak256(a) != keccak256(b)); 83 | 84 | vm.expectEmit(false, false, false, true); 85 | emit log("Error: a == b not satisfied [bytes]"); 86 | t._assertEq(a, b, EXPECT_FAIL); 87 | } 88 | 89 | function testAssertEq_BytesErr_Pass(bytes calldata a, bytes calldata b) external { 90 | vm.assume(keccak256(a) == keccak256(b)); 91 | 92 | t._assertEq(a, b, CUSTOM_ERROR, EXPECT_PASS); 93 | } 94 | 95 | function testAssertEq_BytesErr_Fail(bytes calldata a, bytes calldata b) external { 96 | vm.assume(keccak256(a) != keccak256(b)); 97 | 98 | vm.expectEmit(true, false, false, true); 99 | emit log_named_string("Error", CUSTOM_ERROR); 100 | t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); 101 | } 102 | 103 | /*////////////////////////////////////////////////////////////////////////// 104 | APPROX_EQ_ABS(UINT) 105 | //////////////////////////////////////////////////////////////////////////*/ 106 | 107 | function testAssertApproxEqAbs_Uint_Pass(uint256 a, uint256 b, uint256 maxDelta) external { 108 | vm.assume(stdMath.delta(a, b) <= maxDelta); 109 | 110 | t._assertApproxEqAbs(a, b, maxDelta, EXPECT_PASS); 111 | } 112 | 113 | function testAssertApproxEqAbs_Uint_Fail(uint256 a, uint256 b, uint256 maxDelta) external { 114 | vm.assume(stdMath.delta(a, b) > maxDelta); 115 | 116 | vm.expectEmit(false, false, false, true); 117 | emit log("Error: a ~= b not satisfied [uint]"); 118 | t._assertApproxEqAbs(a, b, maxDelta, EXPECT_FAIL); 119 | } 120 | 121 | function testAssertApproxEqAbs_UintErr_Pass(uint256 a, uint256 b, uint256 maxDelta) external { 122 | vm.assume(stdMath.delta(a, b) <= maxDelta); 123 | 124 | t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_PASS); 125 | } 126 | 127 | function testAssertApproxEqAbs_UintErr_Fail(uint256 a, uint256 b, uint256 maxDelta) external { 128 | vm.assume(stdMath.delta(a, b) > maxDelta); 129 | 130 | vm.expectEmit(true, false, false, true); 131 | emit log_named_string("Error", CUSTOM_ERROR); 132 | t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_FAIL); 133 | } 134 | 135 | /*////////////////////////////////////////////////////////////////////////// 136 | APPROX_EQ_ABS(INT) 137 | //////////////////////////////////////////////////////////////////////////*/ 138 | 139 | function testAssertApproxEqAbs_Int_Pass(int256 a, int256 b, uint256 maxDelta) external { 140 | vm.assume(stdMath.delta(a, b) <= maxDelta); 141 | 142 | t._assertApproxEqAbs(a, b, maxDelta, EXPECT_PASS); 143 | } 144 | 145 | function testAssertApproxEqAbs_Int_Fail(int256 a, int256 b, uint256 maxDelta) external { 146 | vm.assume(stdMath.delta(a, b) > maxDelta); 147 | 148 | vm.expectEmit(false, false, false, true); 149 | emit log("Error: a ~= b not satisfied [int]"); 150 | t._assertApproxEqAbs(a, b, maxDelta, EXPECT_FAIL); 151 | } 152 | 153 | function testAssertApproxEqAbs_IntErr_Pass(int256 a, int256 b, uint256 maxDelta) external { 154 | vm.assume(stdMath.delta(a, b) <= maxDelta); 155 | 156 | t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_PASS); 157 | } 158 | 159 | function testAssertApproxEqAbs_IntErr_Fail(int256 a, int256 b, uint256 maxDelta) external { 160 | vm.assume(stdMath.delta(a, b) > maxDelta); 161 | 162 | vm.expectEmit(true, false, false, true); 163 | emit log_named_string("Error", CUSTOM_ERROR); 164 | t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_FAIL); 165 | } 166 | 167 | /*////////////////////////////////////////////////////////////////////////// 168 | APPROX_EQ_REL(UINT) 169 | //////////////////////////////////////////////////////////////////////////*/ 170 | 171 | function testAssertApproxEqRel_Uint_Pass(uint256 a, uint256 b, uint256 maxPercentDelta) external { 172 | vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); 173 | vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); 174 | 175 | t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_PASS); 176 | } 177 | 178 | function testAssertApproxEqRel_Uint_Fail(uint256 a, uint256 b, uint256 maxPercentDelta) external { 179 | vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); 180 | vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); 181 | 182 | vm.expectEmit(false, false, false, true); 183 | emit log("Error: a ~= b not satisfied [uint]"); 184 | t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_FAIL); 185 | } 186 | 187 | function testAssertApproxEqRel_UintErr_Pass(uint256 a, uint256 b, uint256 maxPercentDelta) external { 188 | vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); 189 | vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); 190 | 191 | t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_PASS); 192 | } 193 | 194 | function testAssertApproxEqRel_UintErr_Fail(uint256 a, uint256 b, uint256 maxPercentDelta) external { 195 | vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); 196 | vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); 197 | 198 | vm.expectEmit(true, false, false, true); 199 | emit log_named_string("Error", CUSTOM_ERROR); 200 | t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_FAIL); 201 | } 202 | 203 | /*////////////////////////////////////////////////////////////////////////// 204 | APPROX_EQ_REL(INT) 205 | //////////////////////////////////////////////////////////////////////////*/ 206 | 207 | function testAssertApproxEqRel_Int_Pass(int128 a, int128 b, uint128 maxPercentDelta) external { 208 | vm.assume(b != 0); 209 | vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); 210 | 211 | t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_PASS); 212 | } 213 | 214 | function testAssertApproxEqRel_Int_Fail(int128 a, int128 b, uint128 maxPercentDelta) external { 215 | vm.assume(b != 0); 216 | vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); 217 | 218 | vm.expectEmit(false, false, false, true); 219 | emit log("Error: a ~= b not satisfied [int]"); 220 | t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_FAIL); 221 | } 222 | 223 | function testAssertApproxEqRel_IntErr_Pass(int128 a, int128 b, uint128 maxPercentDelta) external { 224 | vm.assume(b != 0); 225 | vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); 226 | 227 | t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_PASS); 228 | } 229 | 230 | function testAssertApproxEqRel_IntErr_Fail(int128 a, int128 b, uint128 maxPercentDelta) external { 231 | vm.assume(b != 0); 232 | vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); 233 | 234 | vm.expectEmit(true, false, false, true); 235 | emit log_named_string("Error", CUSTOM_ERROR); 236 | t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_FAIL); 237 | } 238 | } 239 | 240 | 241 | contract TestTest is Test 242 | { 243 | modifier expectFailure(bool expectFail) { 244 | bool preState = vm.load(HEVM_ADDRESS, bytes32("failed")) != bytes32(0x00); 245 | _; 246 | bool postState = vm.load(HEVM_ADDRESS, bytes32("failed")) != bytes32(0x00); 247 | 248 | if (preState == true) { 249 | return; 250 | } 251 | 252 | if (expectFail) { 253 | require(postState == true, "expected failure not triggered"); 254 | 255 | // unwind the expected failure 256 | vm.store(HEVM_ADDRESS, bytes32("failed"), bytes32(uint256(0x00))); 257 | } else { 258 | require(postState == false, "unexpected failure was triggered"); 259 | } 260 | } 261 | 262 | function _assertFalse(bool data, bool expectFail) external expectFailure(expectFail) { 263 | assertFalse(data); 264 | } 265 | 266 | function _assertFalse(bool data, string memory err, bool expectFail) external expectFailure(expectFail) { 267 | assertFalse(data, err); 268 | } 269 | 270 | function _assertEq(bool a, bool b, bool expectFail) external expectFailure(expectFail) { 271 | assertEq(a, b); 272 | } 273 | 274 | function _assertEq(bool a, bool b, string memory err, bool expectFail) external expectFailure(expectFail) { 275 | assertEq(a, b, err); 276 | } 277 | 278 | function _assertEq(bytes memory a, bytes memory b, bool expectFail) external expectFailure(expectFail) { 279 | assertEq(a, b); 280 | } 281 | 282 | function _assertEq(bytes memory a, 283 | bytes memory b, 284 | string memory err, 285 | bool expectFail 286 | ) external expectFailure(expectFail) { 287 | assertEq(a, b, err); 288 | } 289 | 290 | function _assertApproxEqAbs( 291 | uint256 a, 292 | uint256 b, 293 | uint256 maxDelta, 294 | bool expectFail 295 | ) external expectFailure(expectFail) { 296 | assertApproxEqAbs(a, b, maxDelta); 297 | } 298 | 299 | function _assertApproxEqAbs( 300 | uint256 a, 301 | uint256 b, 302 | uint256 maxDelta, 303 | string memory err, 304 | bool expectFail 305 | ) external expectFailure(expectFail) { 306 | assertApproxEqAbs(a, b, maxDelta, err); 307 | } 308 | 309 | function _assertApproxEqAbs( 310 | int256 a, 311 | int256 b, 312 | uint256 maxDelta, 313 | bool expectFail 314 | ) external expectFailure(expectFail) { 315 | assertApproxEqAbs(a, b, maxDelta); 316 | } 317 | 318 | function _assertApproxEqAbs( 319 | int256 a, 320 | int256 b, 321 | uint256 maxDelta, 322 | string memory err, 323 | bool expectFail 324 | ) external expectFailure(expectFail) { 325 | assertApproxEqAbs(a, b, maxDelta, err); 326 | } 327 | 328 | function _assertApproxEqRel( 329 | uint256 a, 330 | uint256 b, 331 | uint256 maxPercentDelta, 332 | bool expectFail 333 | ) external expectFailure(expectFail) { 334 | assertApproxEqRel(a, b, maxPercentDelta); 335 | } 336 | 337 | function _assertApproxEqRel( 338 | uint256 a, 339 | uint256 b, 340 | uint256 maxPercentDelta, 341 | string memory err, 342 | bool expectFail 343 | ) external expectFailure(expectFail) { 344 | assertApproxEqRel(a, b, maxPercentDelta, err); 345 | } 346 | 347 | function _assertApproxEqRel( 348 | int256 a, 349 | int256 b, 350 | uint256 maxPercentDelta, 351 | bool expectFail 352 | ) external expectFailure(expectFail) { 353 | assertApproxEqRel(a, b, maxPercentDelta); 354 | } 355 | 356 | function _assertApproxEqRel( 357 | int256 a, 358 | int256 b, 359 | uint256 maxPercentDelta, 360 | string memory err, 361 | bool expectFail 362 | ) external expectFailure(expectFail) { 363 | assertApproxEqRel(a, b, maxPercentDelta, err); 364 | } 365 | } 366 | -------------------------------------------------------------------------------- /foundry/lib/ds-test/src/test.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | pragma solidity >=0.5.0; 17 | 18 | contract DSTest { 19 | event log (string); 20 | event logs (bytes); 21 | 22 | event log_address (address); 23 | event log_bytes32 (bytes32); 24 | event log_int (int); 25 | event log_uint (uint); 26 | event log_bytes (bytes); 27 | event log_string (string); 28 | 29 | event log_named_address (string key, address val); 30 | event log_named_bytes32 (string key, bytes32 val); 31 | event log_named_decimal_int (string key, int val, uint decimals); 32 | event log_named_decimal_uint (string key, uint val, uint decimals); 33 | event log_named_int (string key, int val); 34 | event log_named_uint (string key, uint val); 35 | event log_named_bytes (string key, bytes val); 36 | event log_named_string (string key, string val); 37 | 38 | bool public IS_TEST = true; 39 | bool private _failed; 40 | 41 | address constant HEVM_ADDRESS = 42 | address(bytes20(uint160(uint256(keccak256('hevm cheat code'))))); 43 | 44 | modifier mayRevert() { _; } 45 | modifier testopts(string memory) { _; } 46 | 47 | function failed() public returns (bool) { 48 | if (_failed) { 49 | return _failed; 50 | } else { 51 | bool globalFailed = false; 52 | if (hasHEVMContext()) { 53 | (, bytes memory retdata) = HEVM_ADDRESS.call( 54 | abi.encodePacked( 55 | bytes4(keccak256("load(address,bytes32)")), 56 | abi.encode(HEVM_ADDRESS, bytes32("failed")) 57 | ) 58 | ); 59 | globalFailed = abi.decode(retdata, (bool)); 60 | } 61 | return globalFailed; 62 | } 63 | } 64 | 65 | function fail() internal { 66 | if (hasHEVMContext()) { 67 | (bool status, ) = HEVM_ADDRESS.call( 68 | abi.encodePacked( 69 | bytes4(keccak256("store(address,bytes32,bytes32)")), 70 | abi.encode(HEVM_ADDRESS, bytes32("failed"), bytes32(uint256(0x01))) 71 | ) 72 | ); 73 | status; // Silence compiler warnings 74 | } 75 | _failed = true; 76 | } 77 | 78 | function hasHEVMContext() internal view returns (bool) { 79 | uint256 hevmCodeSize = 0; 80 | assembly { 81 | hevmCodeSize := extcodesize(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D) 82 | } 83 | return hevmCodeSize > 0; 84 | } 85 | 86 | modifier logs_gas() { 87 | uint startGas = gasleft(); 88 | _; 89 | uint endGas = gasleft(); 90 | emit log_named_uint("gas", startGas - endGas); 91 | } 92 | 93 | function assertTrue(bool condition) internal { 94 | if (!condition) { 95 | emit log("Error: Assertion Failed"); 96 | fail(); 97 | } 98 | } 99 | 100 | function assertTrue(bool condition, string memory err) internal { 101 | if (!condition) { 102 | emit log_named_string("Error", err); 103 | assertTrue(condition); 104 | } 105 | } 106 | 107 | function assertEq(address a, address b) internal { 108 | if (a != b) { 109 | emit log("Error: a == b not satisfied [address]"); 110 | emit log_named_address(" Expected", b); 111 | emit log_named_address(" Actual", a); 112 | fail(); 113 | } 114 | } 115 | function assertEq(address a, address b, string memory err) internal { 116 | if (a != b) { 117 | emit log_named_string ("Error", err); 118 | assertEq(a, b); 119 | } 120 | } 121 | 122 | function assertEq(bytes32 a, bytes32 b) internal { 123 | if (a != b) { 124 | emit log("Error: a == b not satisfied [bytes32]"); 125 | emit log_named_bytes32(" Expected", b); 126 | emit log_named_bytes32(" Actual", a); 127 | fail(); 128 | } 129 | } 130 | function assertEq(bytes32 a, bytes32 b, string memory err) internal { 131 | if (a != b) { 132 | emit log_named_string ("Error", err); 133 | assertEq(a, b); 134 | } 135 | } 136 | function assertEq32(bytes32 a, bytes32 b) internal { 137 | assertEq(a, b); 138 | } 139 | function assertEq32(bytes32 a, bytes32 b, string memory err) internal { 140 | assertEq(a, b, err); 141 | } 142 | 143 | function assertEq(int a, int b) internal { 144 | if (a != b) { 145 | emit log("Error: a == b not satisfied [int]"); 146 | emit log_named_int(" Expected", b); 147 | emit log_named_int(" Actual", a); 148 | fail(); 149 | } 150 | } 151 | function assertEq(int a, int b, string memory err) internal { 152 | if (a != b) { 153 | emit log_named_string("Error", err); 154 | assertEq(a, b); 155 | } 156 | } 157 | function assertEq(uint a, uint b) internal { 158 | if (a != b) { 159 | emit log("Error: a == b not satisfied [uint]"); 160 | emit log_named_uint(" Expected", b); 161 | emit log_named_uint(" Actual", a); 162 | fail(); 163 | } 164 | } 165 | function assertEq(uint a, uint b, string memory err) internal { 166 | if (a != b) { 167 | emit log_named_string("Error", err); 168 | assertEq(a, b); 169 | } 170 | } 171 | function assertEqDecimal(int a, int b, uint decimals) internal { 172 | if (a != b) { 173 | emit log("Error: a == b not satisfied [decimal int]"); 174 | emit log_named_decimal_int(" Expected", b, decimals); 175 | emit log_named_decimal_int(" Actual", a, decimals); 176 | fail(); 177 | } 178 | } 179 | function assertEqDecimal(int a, int b, uint decimals, string memory err) internal { 180 | if (a != b) { 181 | emit log_named_string("Error", err); 182 | assertEqDecimal(a, b, decimals); 183 | } 184 | } 185 | function assertEqDecimal(uint a, uint b, uint decimals) internal { 186 | if (a != b) { 187 | emit log("Error: a == b not satisfied [decimal uint]"); 188 | emit log_named_decimal_uint(" Expected", b, decimals); 189 | emit log_named_decimal_uint(" Actual", a, decimals); 190 | fail(); 191 | } 192 | } 193 | function assertEqDecimal(uint a, uint b, uint decimals, string memory err) internal { 194 | if (a != b) { 195 | emit log_named_string("Error", err); 196 | assertEqDecimal(a, b, decimals); 197 | } 198 | } 199 | 200 | function assertGt(uint a, uint b) internal { 201 | if (a <= b) { 202 | emit log("Error: a > b not satisfied [uint]"); 203 | emit log_named_uint(" Value a", a); 204 | emit log_named_uint(" Value b", b); 205 | fail(); 206 | } 207 | } 208 | function assertGt(uint a, uint b, string memory err) internal { 209 | if (a <= b) { 210 | emit log_named_string("Error", err); 211 | assertGt(a, b); 212 | } 213 | } 214 | function assertGt(int a, int b) internal { 215 | if (a <= b) { 216 | emit log("Error: a > b not satisfied [int]"); 217 | emit log_named_int(" Value a", a); 218 | emit log_named_int(" Value b", b); 219 | fail(); 220 | } 221 | } 222 | function assertGt(int a, int b, string memory err) internal { 223 | if (a <= b) { 224 | emit log_named_string("Error", err); 225 | assertGt(a, b); 226 | } 227 | } 228 | function assertGtDecimal(int a, int b, uint decimals) internal { 229 | if (a <= b) { 230 | emit log("Error: a > b not satisfied [decimal int]"); 231 | emit log_named_decimal_int(" Value a", a, decimals); 232 | emit log_named_decimal_int(" Value b", b, decimals); 233 | fail(); 234 | } 235 | } 236 | function assertGtDecimal(int a, int b, uint decimals, string memory err) internal { 237 | if (a <= b) { 238 | emit log_named_string("Error", err); 239 | assertGtDecimal(a, b, decimals); 240 | } 241 | } 242 | function assertGtDecimal(uint a, uint b, uint decimals) internal { 243 | if (a <= b) { 244 | emit log("Error: a > b not satisfied [decimal uint]"); 245 | emit log_named_decimal_uint(" Value a", a, decimals); 246 | emit log_named_decimal_uint(" Value b", b, decimals); 247 | fail(); 248 | } 249 | } 250 | function assertGtDecimal(uint a, uint b, uint decimals, string memory err) internal { 251 | if (a <= b) { 252 | emit log_named_string("Error", err); 253 | assertGtDecimal(a, b, decimals); 254 | } 255 | } 256 | 257 | function assertGe(uint a, uint b) internal { 258 | if (a < b) { 259 | emit log("Error: a >= b not satisfied [uint]"); 260 | emit log_named_uint(" Value a", a); 261 | emit log_named_uint(" Value b", b); 262 | fail(); 263 | } 264 | } 265 | function assertGe(uint a, uint b, string memory err) internal { 266 | if (a < b) { 267 | emit log_named_string("Error", err); 268 | assertGe(a, b); 269 | } 270 | } 271 | function assertGe(int a, int b) internal { 272 | if (a < b) { 273 | emit log("Error: a >= b not satisfied [int]"); 274 | emit log_named_int(" Value a", a); 275 | emit log_named_int(" Value b", b); 276 | fail(); 277 | } 278 | } 279 | function assertGe(int a, int b, string memory err) internal { 280 | if (a < b) { 281 | emit log_named_string("Error", err); 282 | assertGe(a, b); 283 | } 284 | } 285 | function assertGeDecimal(int a, int b, uint decimals) internal { 286 | if (a < b) { 287 | emit log("Error: a >= b not satisfied [decimal int]"); 288 | emit log_named_decimal_int(" Value a", a, decimals); 289 | emit log_named_decimal_int(" Value b", b, decimals); 290 | fail(); 291 | } 292 | } 293 | function assertGeDecimal(int a, int b, uint decimals, string memory err) internal { 294 | if (a < b) { 295 | emit log_named_string("Error", err); 296 | assertGeDecimal(a, b, decimals); 297 | } 298 | } 299 | function assertGeDecimal(uint a, uint b, uint decimals) internal { 300 | if (a < b) { 301 | emit log("Error: a >= b not satisfied [decimal uint]"); 302 | emit log_named_decimal_uint(" Value a", a, decimals); 303 | emit log_named_decimal_uint(" Value b", b, decimals); 304 | fail(); 305 | } 306 | } 307 | function assertGeDecimal(uint a, uint b, uint decimals, string memory err) internal { 308 | if (a < b) { 309 | emit log_named_string("Error", err); 310 | assertGeDecimal(a, b, decimals); 311 | } 312 | } 313 | 314 | function assertLt(uint a, uint b) internal { 315 | if (a >= b) { 316 | emit log("Error: a < b not satisfied [uint]"); 317 | emit log_named_uint(" Value a", a); 318 | emit log_named_uint(" Value b", b); 319 | fail(); 320 | } 321 | } 322 | function assertLt(uint a, uint b, string memory err) internal { 323 | if (a >= b) { 324 | emit log_named_string("Error", err); 325 | assertLt(a, b); 326 | } 327 | } 328 | function assertLt(int a, int b) internal { 329 | if (a >= b) { 330 | emit log("Error: a < b not satisfied [int]"); 331 | emit log_named_int(" Value a", a); 332 | emit log_named_int(" Value b", b); 333 | fail(); 334 | } 335 | } 336 | function assertLt(int a, int b, string memory err) internal { 337 | if (a >= b) { 338 | emit log_named_string("Error", err); 339 | assertLt(a, b); 340 | } 341 | } 342 | function assertLtDecimal(int a, int b, uint decimals) internal { 343 | if (a >= b) { 344 | emit log("Error: a < b not satisfied [decimal int]"); 345 | emit log_named_decimal_int(" Value a", a, decimals); 346 | emit log_named_decimal_int(" Value b", b, decimals); 347 | fail(); 348 | } 349 | } 350 | function assertLtDecimal(int a, int b, uint decimals, string memory err) internal { 351 | if (a >= b) { 352 | emit log_named_string("Error", err); 353 | assertLtDecimal(a, b, decimals); 354 | } 355 | } 356 | function assertLtDecimal(uint a, uint b, uint decimals) internal { 357 | if (a >= b) { 358 | emit log("Error: a < b not satisfied [decimal uint]"); 359 | emit log_named_decimal_uint(" Value a", a, decimals); 360 | emit log_named_decimal_uint(" Value b", b, decimals); 361 | fail(); 362 | } 363 | } 364 | function assertLtDecimal(uint a, uint b, uint decimals, string memory err) internal { 365 | if (a >= b) { 366 | emit log_named_string("Error", err); 367 | assertLtDecimal(a, b, decimals); 368 | } 369 | } 370 | 371 | function assertLe(uint a, uint b) internal { 372 | if (a > b) { 373 | emit log("Error: a <= b not satisfied [uint]"); 374 | emit log_named_uint(" Value a", a); 375 | emit log_named_uint(" Value b", b); 376 | fail(); 377 | } 378 | } 379 | function assertLe(uint a, uint b, string memory err) internal { 380 | if (a > b) { 381 | emit log_named_string("Error", err); 382 | assertLe(a, b); 383 | } 384 | } 385 | function assertLe(int a, int b) internal { 386 | if (a > b) { 387 | emit log("Error: a <= b not satisfied [int]"); 388 | emit log_named_int(" Value a", a); 389 | emit log_named_int(" Value b", b); 390 | fail(); 391 | } 392 | } 393 | function assertLe(int a, int b, string memory err) internal { 394 | if (a > b) { 395 | emit log_named_string("Error", err); 396 | assertLe(a, b); 397 | } 398 | } 399 | function assertLeDecimal(int a, int b, uint decimals) internal { 400 | if (a > b) { 401 | emit log("Error: a <= b not satisfied [decimal int]"); 402 | emit log_named_decimal_int(" Value a", a, decimals); 403 | emit log_named_decimal_int(" Value b", b, decimals); 404 | fail(); 405 | } 406 | } 407 | function assertLeDecimal(int a, int b, uint decimals, string memory err) internal { 408 | if (a > b) { 409 | emit log_named_string("Error", err); 410 | assertLeDecimal(a, b, decimals); 411 | } 412 | } 413 | function assertLeDecimal(uint a, uint b, uint decimals) internal { 414 | if (a > b) { 415 | emit log("Error: a <= b not satisfied [decimal uint]"); 416 | emit log_named_decimal_uint(" Value a", a, decimals); 417 | emit log_named_decimal_uint(" Value b", b, decimals); 418 | fail(); 419 | } 420 | } 421 | function assertLeDecimal(uint a, uint b, uint decimals, string memory err) internal { 422 | if (a > b) { 423 | emit log_named_string("Error", err); 424 | assertGeDecimal(a, b, decimals); 425 | } 426 | } 427 | 428 | function assertEq(string memory a, string memory b) internal { 429 | if (keccak256(abi.encodePacked(a)) != keccak256(abi.encodePacked(b))) { 430 | emit log("Error: a == b not satisfied [string]"); 431 | emit log_named_string(" Value a", a); 432 | emit log_named_string(" Value b", b); 433 | fail(); 434 | } 435 | } 436 | function assertEq(string memory a, string memory b, string memory err) internal { 437 | if (keccak256(abi.encodePacked(a)) != keccak256(abi.encodePacked(b))) { 438 | emit log_named_string("Error", err); 439 | assertEq(a, b); 440 | } 441 | } 442 | 443 | function checkEq0(bytes memory a, bytes memory b) internal pure returns (bool ok) { 444 | ok = true; 445 | if (a.length == b.length) { 446 | for (uint i = 0; i < a.length; i++) { 447 | if (a[i] != b[i]) { 448 | ok = false; 449 | } 450 | } 451 | } else { 452 | ok = false; 453 | } 454 | } 455 | function assertEq0(bytes memory a, bytes memory b) internal { 456 | if (!checkEq0(a, b)) { 457 | emit log("Error: a == b not satisfied [bytes]"); 458 | emit log_named_bytes(" Expected", a); 459 | emit log_named_bytes(" Actual", b); 460 | fail(); 461 | } 462 | } 463 | function assertEq0(bytes memory a, bytes memory b, string memory err) internal { 464 | if (!checkEq0(a, b)) { 465 | emit log_named_string("Error", err); 466 | assertEq0(a, b); 467 | } 468 | } 469 | } 470 | -------------------------------------------------------------------------------- /hardhat/findUniswapClones.js: -------------------------------------------------------------------------------- 1 | // findUniswapClones 2 | const path = require('path'); 3 | require('dotenv').config({path:path.resolve('../', '.env')}); 4 | const fs = require('fs'); 5 | const axios = require('axios'); 6 | const { providers, utils } = require("ethers"); 7 | // const { Interface } = require("@ethersproject/abi"); 8 | // const { addABI, getABIs } = require("abi-decoder"); 9 | // const { EVM } = require("evm"); 10 | const { inspect } = require('util'); 11 | 12 | const deepLogs = (obj) => { 13 | return inspect(obj, {depth: 5}); 14 | } 15 | 16 | const findMatches = (clone, org, debug) => { 17 | const clone_filter = clone.filter( a => { 18 | return a.type == 'function' ? true : false; 19 | }) 20 | const org_filter = org.filter( b => { 21 | return b.type == 'function' ? true : false; 22 | }) 23 | // if(debug) console.log('abi fn filter',clone_filter, org_filter); 24 | 25 | const finds = org_filter.filter( j => { 26 | return clone_filter.some( k => { 27 | // if(debug) console.log('j.name == k.name', j.name, k.name); 28 | return j.name == k.name ? true : false; 29 | }); 30 | }); 31 | // if(debug) console.log('finds',finds); 32 | return finds; 33 | } 34 | const arrayUnique = (array) => { 35 | var a = array.concat(); 36 | for(var i=0; i `https://api.etherscan.io/api?module=contract&action=getabi&address=${a}&apikey=${ETHERSCAN_APIKEY}`; 54 | 55 | // const ETHEREUM_RPC_URL = `https://mainnet.infura.io/v3/${INFURA_APIKEY}`; 56 | const ETHEREUM_RPC_URL = `https://api.archivenode.io/${ARCHIVENODE_APIKEY}`; 57 | 58 | const provider = new providers.StaticJsonRpcProvider(ETHEREUM_RPC_URL); 59 | // const provider = new providers.JsonRpcProvider(ETHEREUM_RPC_URL); 60 | // const provider = new providers.getDefaultProvider(ETHEREUM_RPC_URL); 61 | 62 | console.log('start --'); 63 | console.log('ETHEREUM_RPC_URL',ETHEREUM_RPC_URL); 64 | 65 | const getBlockNumber = async (n, debug) => { 66 | const blockNumber = await provider.getBlockNumber(); 67 | const blocksPerDay = 6600; 68 | LATEST_BLOCK = blockNumber; 69 | START_SCANNED_BLOCK = blockNumber - (n * blocksPerDay); 70 | if(debug) console.log('latest block',blockNumber); 71 | if(debug) console.log('blocks not scanned',START_SCANNED_BLOCK); 72 | readNumOfBlocks(START_SCANNED_BLOCK, 0, PENDING_BLOCK_SCANNED, 2000, true); 73 | return blockNumber; 74 | } 75 | 76 | const getBlock = async (blockNumber, debug) => { 77 | const block = await provider.getBlockWithTransactions(blockNumber); 78 | // if(debug) console.log('block',block); 79 | return block; 80 | } 81 | 82 | const getABI = async (a, debug) => { 83 | 84 | const api_url = ETHERSCAN_ABI_ENDPOINT(a); 85 | // if(debug) console.log('api -- ',api_url); 86 | 87 | const config = { 88 | timeout: 30000, 89 | url: api_url, 90 | method: 'get', 91 | responseType: 'json' 92 | }; 93 | const res = await axios(config); 94 | const data = res.data; 95 | // if(debug) console.log('data -- ',api_url, deepLogs(data) ); 96 | if(debug) { 97 | if(res.status != 200) console.log('res --', deepLogs(data) ); 98 | } 99 | return data; 100 | } 101 | 102 | const readBlock = async (blockNumber, debug) => { 103 | 104 | let contract_trs = []; 105 | if(debug) console.log('block',blockNumber); 106 | 107 | let block = await getBlock(blockNumber); 108 | let txs = block.transactions; 109 | let j=0; 110 | for(j=0;j 10 ){ 126 | // if(debug) console.log('contract ABI', ABI); 127 | if(debug) console.log('contract ABI matches', matches.length); 128 | t.ABIMatches = matches.length; 129 | contract_trs.push(t); 130 | } 131 | } 132 | // else if(t.data != ''){ 133 | // let evm = new EVM(t.data); 134 | // if(evm){ 135 | // let ABIfunctions = evm.getFunctions().map( f => 'function '+ f); 136 | // // let ABIevents = evm.getEvents().map( e => 'event '+ e); 137 | // // let ABISignatures = arrayUnique(ABIfunctions.concat(ABIevents)); 138 | // // if(debug) console.log('contract evm abi', ABISignatures); 139 | // if(ABIfunctions){ 140 | // ABIfunctions.map(async s => { 141 | // // if(debug) console.log('abi signature', s); 142 | // try { 143 | // let i = new Interface([s]); 144 | // await addABI(i.fragments); 145 | // } catch (e) { 146 | // console.log(e); 147 | // } 148 | // }); 149 | // let ABI = getABIs(); 150 | // // if(debug) console.log('contract ABI', deepLogs(ABI)); 151 | // let matches = findMatches(ABI, UNIV2_ABI, true); 152 | // // high matches means high possibility clone 153 | // if(matches.length > 10 ){ 154 | // // if(debug) console.log('contract ABI', ABI); 155 | // if(debug) console.log('contract ABI matches', matches.length); 156 | // t.ABIMatches = matches.length; 157 | // contract_trs.push(t); 158 | // } 159 | // } 160 | // } 161 | // } 162 | } 163 | } 164 | } 165 | if(debug) console.log('contract creation trxs',contract_trs); 166 | if(contract_trs.length > 0){ 167 | contract_trs.map( async c => { 168 | let cobj = { 169 | "block":c.blockNumber, 170 | "hash": c.hash, 171 | "address": c.creates, 172 | "ABIMatches": c.ABIMatches 173 | } 174 | let clonesArr = await require(`./json/uniswap-v2-clones.json`); 175 | clonesArr.push(cobj); 176 | // if(debug) console.log('clonesArr ',clonesArr); 177 | await fs.writeFile(`${__dirname}/json/uniswap-v2-clones.json`, JSON.stringify(clonesArr), console.error); 178 | }) 179 | } 180 | } 181 | 182 | const readNumOfBlocks = async (blockNumber, inc, num, inter, debug) => { 183 | setTimeout(() => { 184 | inc++; 185 | // if(debug) console.log('blockNumber' ,blockNumber+inc); 186 | blockNumber+inc < blockNumber+num ? readNumOfBlocks(blockNumber, inc, num, inter, debug) : null; 187 | readBlock(blockNumber+inc, true); 188 | },inter); 189 | } 190 | 191 | let LATEST_BLOCK = 0, START_SCANNED_BLOCK = 0, PENDING_BLOCK_SCANNED = 20000; 192 | 193 | getBlockNumber(3, true); 194 | // findMatches(CLONE_UNIV2_ABI,UNIV2_ABI, true); 195 | 196 | // clones found through scanning 197 | // block - 10207935 198 | // hash - 0x81af8d6b76f4d137e02b16e02360ae6499ac6f00c626285be8623999c6c756c2 199 | // address - 0xe8a97dec33e253d57fa1497b2f98ed0f5bd26fb4 200 | // ABIMatches - 19 201 | 202 | // block - 10208935 203 | // hash - 0x407d6cf6654cd5b6f6d1f5fddc5174d38df81f2ad010cf801ae773400097886f 204 | // address - 0x61a27dfD4aa512D0666Ac3095ad8918581835f86 205 | // ABIMatches - 19 206 | 207 | // block 10214723 208 | // hash - 0x0067d8b525591f37602696fe976689e89ddb098fcb0d315d9a90b87ef40e9494 209 | // address 0x96CEe07b886ceeE5b58Bcc4B2cc192b4A77ba31B 210 | // ABIMatches 19 211 | 212 | // block 10227631 213 | // hash - 0xbe90f23c73bdcd8839eb60730023d8f795bf9b0d988cb458902942903a32f7a7 214 | // address 0xadB090336899B1f0306a1B1D392884Aa87201aBa 215 | // ABIMatches 19 216 | 217 | module.exports = { 218 | readNumOfBlocks 219 | } 220 | return; 221 | 222 | --------------------------------------------------------------------------------