├── packages ├── foundry │ ├── script │ │ └── .gitkeep │ ├── src │ │ └── .gitkeep │ ├── test │ │ └── .gitkeep │ ├── .npmignore │ ├── lib │ │ └── forge-std │ │ │ ├── .gitignore │ │ │ ├── lib │ │ │ └── ds-test │ │ │ │ ├── .gitignore │ │ │ │ ├── default.nix │ │ │ │ ├── Makefile │ │ │ │ ├── package.json │ │ │ │ ├── demo │ │ │ │ └── demo.sol │ │ │ │ └── src │ │ │ │ └── test.sol │ │ │ ├── .gitmodules │ │ │ ├── src │ │ │ ├── Components.sol │ │ │ ├── Test.sol │ │ │ ├── Common.sol │ │ │ ├── Script.sol │ │ │ ├── interfaces │ │ │ │ ├── IERC165.sol │ │ │ │ ├── IERC20.sol │ │ │ │ ├── IERC1155.sol │ │ │ │ ├── IERC721.sol │ │ │ │ └── IERC4626.sol │ │ │ ├── StdError.sol │ │ │ ├── StdMath.sol │ │ │ ├── StdJson.sol │ │ │ ├── StdUtils.sol │ │ │ ├── StdAssertions.sol │ │ │ ├── StdStorage.sol │ │ │ └── Vm.sol │ │ │ ├── package.json │ │ │ ├── foundry.toml │ │ │ ├── LICENSE-MIT │ │ │ ├── .github │ │ │ └── workflows │ │ │ │ └── ci.yml │ │ │ ├── test │ │ │ ├── StdError.t.sol │ │ │ ├── StdUtils.t.sol │ │ │ ├── StdMath.t.sol │ │ │ ├── fixtures │ │ │ │ └── broadcast.log.json │ │ │ ├── StdStorage.t.sol │ │ │ └── StdCheats.t.sol │ │ │ ├── README.md │ │ │ └── LICENSE-APACHE │ ├── .gitmodules │ ├── foundry.toml │ ├── package.json │ ├── circuits │ │ └── ExampleCircuit.circom │ ├── .gitignore │ ├── .github │ │ └── workflows │ │ │ └── test.yml │ └── scripts │ │ └── dev.ts ├── tsconfig │ ├── README.md │ ├── package.json │ ├── react-library.json │ ├── base.json │ └── nextjs.json └── eslint-config-custom │ ├── index.js │ └── package.json ├── .npmignore ├── apps └── web │ ├── .gitignore │ ├── .eslintrc.js │ ├── styles │ └── globals.css │ ├── postcss.config.js │ ├── tsconfig.json │ ├── next-env.d.ts │ ├── next.config.js │ ├── pages │ ├── _document.tsx │ ├── _app.tsx │ └── index.tsx │ ├── tailwind.config.js │ ├── package.json │ └── README.md ├── .eslintrc.js ├── turbo.json ├── .gitignore ├── package.json ├── scripts ├── postinstall.ts ├── ptau.sh └── circuits.ts ├── LICENSE └── zk-starter └── README.md /packages/foundry/script/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/foundry/src/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/foundry/test/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .env* 2 | zk/* 3 | 4 | -------------------------------------------------------------------------------- /packages/foundry/.npmignore: -------------------------------------------------------------------------------- 1 | .env* 2 | 3 | -------------------------------------------------------------------------------- /apps/web/.gitignore: -------------------------------------------------------------------------------- 1 | public/* 2 | !public/*.min.js 3 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/.gitignore: -------------------------------------------------------------------------------- 1 | cache/ 2 | out/ 3 | .vscode 4 | .idea 5 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/lib/ds-test/.gitignore: -------------------------------------------------------------------------------- 1 | /.dapple 2 | /build 3 | /out 4 | -------------------------------------------------------------------------------- /apps/web/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ["custom"], 4 | }; 5 | -------------------------------------------------------------------------------- /apps/web/styles/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /apps/web/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /packages/foundry/.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/forge-std"] 2 | path = lib/forge-std 3 | url = https://github.com/foundry-rs/forge-std 4 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/ds-test"] 2 | path = lib/ds-test 3 | url = https://github.com/dapphub/ds-test 4 | -------------------------------------------------------------------------------- /packages/tsconfig/README.md: -------------------------------------------------------------------------------- 1 | # `tsconfig` 2 | 3 | These are base shared `tsconfig.json`s from which all other `tsconfig.json`'s inherit from. 4 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/lib/ds-test/default.nix: -------------------------------------------------------------------------------- 1 | { solidityPackage, dappsys }: solidityPackage { 2 | name = "ds-test"; 3 | src = ./src; 4 | } 5 | -------------------------------------------------------------------------------- /apps/web/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig/nextjs.json", 3 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 4 | "exclude": ["node_modules"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/foundry/foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | src = 'src' 3 | out = 'out' 4 | libs = ['lib'] 5 | 6 | # See more config options https://github.com/foundry-rs/foundry/tree/master/config -------------------------------------------------------------------------------- /packages/eslint-config-custom/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["next", "turbo", "prettier"], 3 | rules: { 4 | "@next/next/no-html-link-for-pages": "off", 5 | "react/jsx-key": "off", 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /packages/tsconfig/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tsconfig", 3 | "version": "0.0.0", 4 | "private": true, 5 | "files": [ 6 | "base.json", 7 | "nextjs.json", 8 | "react-library.json" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /apps/web/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | // This tells ESLint to load the config from the package `eslint-config-custom` 4 | extends: ["custom"], 5 | settings: { 6 | next: { 7 | rootDir: ["apps/*/"], 8 | }, 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /packages/foundry/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foundry", 3 | "version": "0.0.0", 4 | "main": "dist", 5 | "scripts": { 6 | "test": "forge test", 7 | "dev": "ts-node scripts/dev" 8 | }, 9 | "dependencies": { 10 | "ethers": "5.7.2", 11 | "ts-node": "10.9.1" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/tsconfig/react-library.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "React Library", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "jsx": "react-jsx", 7 | "lib": ["ES2015"], 8 | "module": "ESNext", 9 | "target": "es6" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "pipeline": { 4 | "build": { 5 | "dependsOn": ["^build"], 6 | "outputs": ["dist/**", ".next/**"] 7 | }, 8 | "lint": { 9 | "outputs": [] 10 | }, 11 | "dev": { 12 | "cache": false 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /apps/web/next.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | reactStrictMode: true, 3 | webpack: (config) => { 4 | const experiments = config.experiments || {} 5 | config.experiments = { ...experiments, asyncWebAssembly: true } 6 | return config; 7 | }, 8 | experimental: { 9 | transpilePackages: ["foundry"] 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/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 | -------------------------------------------------------------------------------- /packages/foundry/circuits/ExampleCircuit.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | template ExampleCircuit() { 4 | signal input a; 5 | signal input b; 6 | signal output c; 7 | 8 | c <== a*b; 9 | } 10 | 11 | // Input "a" is publicly visible, whereas input "b" is not. 12 | // The result output "c" of the computation is also public. 13 | component main{public [a]} = ExampleCircuit(); 14 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/src/Components.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | import "./console.sol"; 5 | import "./console2.sol"; 6 | import "./StdAssertions.sol"; 7 | import "./StdCheats.sol"; 8 | import "./StdError.sol"; 9 | import "./StdJson.sol"; 10 | import "./StdMath.sol"; 11 | import "./StdStorage.sol"; 12 | import "./StdUtils.sol"; 13 | import "./Vm.sol"; 14 | -------------------------------------------------------------------------------- /packages/foundry/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiler files 2 | cache/ 3 | out/ 4 | 5 | # Ignores development broadcast logs 6 | !/broadcast 7 | /broadcast/*/31337/ 8 | /broadcast/**/dry-run/ 9 | 10 | # Dotenv file 11 | .env* 12 | 13 | # Generated 14 | src/generated 15 | 16 | # Internal distribution 17 | dist/ 18 | 19 | # ExampleCircuit 20 | src/ExampleCircuit.sol 21 | test/ExampleCircuit.t.sol 22 | script/ExampleCircuit.s.sol 23 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/lib/ds-test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ds-test", 3 | "version": "1.0.0", 4 | "description": "Assertions, equality checks and other test helpers ", 5 | "bugs": "https://github.com/dapphub/ds-test/issues", 6 | "license": "GPL-3.0", 7 | "author": "Contributors to ds-test", 8 | "files": [ 9 | "src/*" 10 | ], 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/dapphub/ds-test.git" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/eslint-config-custom/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eslint-config-custom", 3 | "version": "0.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "dependencies": { 7 | "eslint": "^7.23.0", 8 | "eslint-config-next": "13.0.0", 9 | "eslint-config-prettier": "^8.3.0", 10 | "eslint-plugin-react": "7.31.8", 11 | "eslint-config-turbo": "latest" 12 | }, 13 | "devDependencies": { 14 | "typescript": "^4.7.4" 15 | }, 16 | "publishConfig": { 17 | "access": "public" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | .pnp 6 | .pnp.js 7 | 8 | # testing 9 | coverage 10 | 11 | # next.js 12 | .next/ 13 | out/ 14 | build 15 | 16 | # misc 17 | .DS_Store 18 | *.pem 19 | 20 | # debug 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | .pnpm-debug.log* 25 | 26 | # local env files 27 | .env* 28 | 29 | # turbo 30 | .turbo 31 | 32 | # zk 33 | zk/* 34 | 35 | # WebStorm IDE 36 | .idea/ 37 | 38 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/src/Test.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | import {CommonBase} from "./Common.sol"; 5 | import "../lib/ds-test/src/test.sol"; 6 | // forgefmt: disable-next-line 7 | import {console, console2, StdAssertions, StdCheats, stdError, stdJson, stdMath, StdStorage, stdStorage, StdUtils, Vm} from "./Components.sol"; 8 | 9 | abstract contract TestBase is CommonBase {} 10 | 11 | abstract contract Test is TestBase, DSTest, StdAssertions, StdCheats, StdUtils {} 12 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/src/Common.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | import {StdStorage, Vm} from "./Components.sol"; 5 | 6 | abstract contract CommonBase { 7 | address internal constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code")))); 8 | uint256 internal constant UINT256_MAX = 9 | 115792089237316195423570985008687907853269984665640564039457584007913129639935; 10 | 11 | StdStorage internal stdstore; 12 | Vm internal constant vm = Vm(VM_ADDRESS); 13 | } 14 | -------------------------------------------------------------------------------- /apps/web/pages/_document.tsx: -------------------------------------------------------------------------------- 1 | import {Html, Head, Main, NextScript} from 'next/document' 2 | 3 | export default function Document() { 4 | return ( 5 | 6 | 7 | {/* https://tailwindui.com/documentation */} 8 | 9 | {/* eslint-disable-next-line @next/next/no-sync-scripts */} 10 | 11 | 12 |
13 | 14 | 15 | 16 | ); 17 | } -------------------------------------------------------------------------------- /apps/web/tailwind.config.js: -------------------------------------------------------------------------------- 1 | // tailwind.config.js 2 | const defaultTheme = require('tailwindcss/defaultTheme') 3 | 4 | /** @type {import('tailwindcss').Config} */ 5 | module.exports = { 6 | content: [ 7 | './app/**/*.{js,ts,jsx,tsx}', 8 | './pages/**/*.{js,ts,jsx,tsx}', 9 | './components/**/*.{js,ts,jsx,tsx}', 10 | ], 11 | theme: { 12 | extend: { 13 | fontFamily: { 14 | sans: ['Inter var', ...defaultTheme.fontFamily.sans], 15 | }, 16 | }, 17 | }, 18 | plugins: [ 19 | require('@tailwindcss/typography'), 20 | ], 21 | } 22 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/src/Script.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | import {CommonBase} from "./Common.sol"; 5 | // forgefmt: disable-next-line 6 | import {console, console2, StdCheatsSafe, stdJson, stdMath, StdStorage, stdStorageSafe, StdUtils, VmSafe} from "./Components.sol"; 7 | 8 | abstract contract ScriptBase is CommonBase { 9 | VmSafe internal constant vmSafe = VmSafe(VM_ADDRESS); 10 | } 11 | 12 | abstract contract Script is ScriptBase, StdCheatsSafe, StdUtils { 13 | bool public IS_SCRIPT = true; 14 | } 15 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/src/interfaces/IERC165.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.6.2; 2 | 3 | interface IERC165 { 4 | /// @notice Query if a contract implements an interface 5 | /// @param interfaceID The interface identifier, as specified in ERC-165 6 | /// @dev Interface identification is specified in ERC-165. This function 7 | /// uses less than 30,000 gas. 8 | /// @return `true` if the contract implements `interfaceID` and 9 | /// `interfaceID` is not 0xffffffff, `false` otherwise 10 | function supportsInterface(bytes4 interfaceID) external view returns (bool); 11 | } 12 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "forge-std", 3 | "version": "1.0.0", 4 | "description": "Forge Standard Library is a collection of helpful contracts and libraries for use with Forge and Foundry.", 5 | "homepage": "https://book.getfoundry.sh/forge/forge-std", 6 | "bugs": "https://github.com/foundry-rs/forge-std/issues", 7 | "license": "(Apache-2.0 OR MIT)", 8 | "author": "Contributors to Forge Standard Library", 9 | "files": [ 10 | "src/*" 11 | ], 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/foundry-rs/forge-std.git" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/tsconfig/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Default", 4 | "compilerOptions": { 5 | "composite": false, 6 | "declaration": true, 7 | "declarationMap": true, 8 | "esModuleInterop": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "inlineSources": false, 11 | "isolatedModules": true, 12 | "moduleResolution": "node", 13 | "noUnusedLocals": false, 14 | "noUnusedParameters": false, 15 | "preserveWatchOutput": true, 16 | "skipLibCheck": true, 17 | "strict": true 18 | }, 19 | "exclude": ["node_modules"] 20 | } 21 | -------------------------------------------------------------------------------- /packages/tsconfig/nextjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Next.js", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "target": "es5", 7 | "lib": ["dom", "dom.iterable", "esnext"], 8 | "allowJs": true, 9 | "skipLibCheck": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "noEmit": true, 13 | "incremental": true, 14 | "esModuleInterop": true, 15 | "module": "esnext", 16 | "resolveJsonModule": true, 17 | "isolatedModules": true, 18 | "jsx": "preserve" 19 | }, 20 | "include": ["src", "next-env.d.ts"], 21 | "exclude": ["node_modules"] 22 | } 23 | -------------------------------------------------------------------------------- /packages/foundry/.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: workflow_dispatch 4 | 5 | env: 6 | FOUNDRY_PROFILE: ci 7 | 8 | jobs: 9 | check: 10 | strategy: 11 | fail-fast: true 12 | 13 | name: Foundry project 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v3 17 | with: 18 | submodules: recursive 19 | 20 | - name: Install Foundry 21 | uses: foundry-rs/foundry-toolchain@v1 22 | with: 23 | version: nightly 24 | 25 | - name: Run Forge build 26 | run: | 27 | forge --version 28 | forge build --sizes 29 | id: build 30 | 31 | - name: Run Forge tests 32 | run: | 33 | forge test -vvv 34 | id: test 35 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | fs_permissions = [{ access = "read-write", path = "./"}] 3 | 4 | [rpc_endpoints] 5 | # We intentionally use both dashes and underscores in the key names to ensure both are supported. 6 | # The RPC URLs below match the StdChains URLs but append a trailing slash for testing. 7 | mainnet = "https://api.mycryptoapi.com/eth/" 8 | optimism_goerli = "https://goerli.optimism.io/" 9 | arbitrum-one-goerli = "https://goerli-rollup.arbitrum.io/rpc/" 10 | 11 | [fmt] 12 | # These are all the `forge fmt` defaults. 13 | line_length = 120 14 | tab_width = 4 15 | bracket_spacing = false 16 | int_types = 'long' 17 | multiline_func_header = 'attributes_first' 18 | quote_style = 'double' 19 | number_underscore = 'preserve' 20 | single_line_statement_blocks = 'preserve' 21 | ignore = ["src/console.sol", "src/console2.sol"] -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zk-starter", 3 | "version": "0.0.0", 4 | "private": true, 5 | "workspaces": [ 6 | "apps/*", 7 | "packages/*" 8 | ], 9 | "scripts": { 10 | "postinstall": "node_modules/.bin/ts-node scripts/postinstall", 11 | "circuits": "node_modules/.bin/ts-node scripts/circuits", 12 | "build": "turbo run build", 13 | "dev": "turbo run dev --parallel", 14 | "lint": "turbo run lint", 15 | "format": "prettier --write \"**/*.{ts,tsx,md}\"" 16 | }, 17 | "devDependencies": { 18 | "dotenv": "16.0.3", 19 | "eslint-config-custom": "*", 20 | "nanoid": "3.3.0", 21 | "prettier": "latest", 22 | "snarkjs": "0.5.0", 23 | "ts-node": "10.9.1", 24 | "turbo": "latest" 25 | }, 26 | "engines": { 27 | "node": ">=14.0.0" 28 | }, 29 | "dependencies": {}, 30 | "packageManager": "yarn@1.22.19" 31 | } 32 | -------------------------------------------------------------------------------- /apps/web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@rainbow-me/rainbowkit": "0.7.4", 13 | "ethers": "5.7.2", 14 | "ffjavascript": "0.2.57", 15 | "foundry": "*", 16 | "next": "13.0.0", 17 | "react": "18.2.0", 18 | "react-dom": "18.2.0", 19 | "snarkjs": "0.5.0", 20 | "wagmi": "0.7.12" 21 | }, 22 | "devDependencies": { 23 | "@babel/core": "7.19.6", 24 | "@tailwindcss/typography": "0.5.7", 25 | "@types/node": "17.0.45", 26 | "@types/react": "18.0.24", 27 | "@types/react-dom": "18.0.8", 28 | "autoprefixer": "10.4.13", 29 | "eslint": "7.32.0", 30 | "eslint-config-custom": "*", 31 | "postcss": "8.4.18", 32 | "tailwindcss": "^3.2.2", 33 | "tsconfig": "*", 34 | "typescript": "4.8.4" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /scripts/postinstall.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs'; 2 | import * as path from 'path'; 3 | import * as child_process from 'child_process'; 4 | 5 | const buildDir = path.resolve('build'); 6 | 7 | if (!fs.existsSync(buildDir)) 8 | fs.mkdirSync(buildDir); 9 | 10 | const circomDir = path.resolve(buildDir, 'circom'); 11 | 12 | if (!fs.existsSync(circomDir)) 13 | child_process.execSync( 14 | 'git clone https://github.com/iden3/circom.git', 15 | {stdio: 'inherit', cwd: buildDir}, 16 | ); 17 | 18 | const circomBuildPath = path.resolve(buildDir, 'target', 'release'); 19 | 20 | if (!fs.existsSync(circomBuildPath)) 21 | child_process.execSync( 22 | 'cargo build --release && cargo install --path circom', 23 | {stdio: 'inherit', cwd: circomDir}, 24 | ); 25 | 26 | const powersOfTauFinal = path.resolve('build', 'pot15_final.ptau'); // 🦄 27 | 28 | if (!fs.existsSync(powersOfTauFinal)) 29 | child_process.execSync('./scripts/ptau.sh', {stdio: 'inherit'}); 30 | 31 | // Rebuild the circuits. 32 | child_process.execSync('yarn circuits', {stdio: 'inherit'}); 33 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/src/StdError.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // Panics work for versions >=0.8.0, but we lowered the pragma to make this compatible with Test 3 | pragma solidity >=0.6.2 <0.9.0; 4 | 5 | library stdError { 6 | bytes public constant assertionError = abi.encodeWithSignature("Panic(uint256)", 0x01); 7 | bytes public constant arithmeticError = abi.encodeWithSignature("Panic(uint256)", 0x11); 8 | bytes public constant divisionError = abi.encodeWithSignature("Panic(uint256)", 0x12); 9 | bytes public constant enumConversionError = abi.encodeWithSignature("Panic(uint256)", 0x21); 10 | bytes public constant encodeStorageError = abi.encodeWithSignature("Panic(uint256)", 0x22); 11 | bytes public constant popError = abi.encodeWithSignature("Panic(uint256)", 0x31); 12 | bytes public constant indexOOBError = abi.encodeWithSignature("Panic(uint256)", 0x32); 13 | bytes public constant memOverflowError = abi.encodeWithSignature("Panic(uint256)", 0x41); 14 | bytes public constant zeroVarError = abi.encodeWithSignature("Panic(uint256)", 0x51); 15 | } 16 | -------------------------------------------------------------------------------- /LICENSE/zk-starter: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 cawfree 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright Contributors to Forge Standard Library 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 | -------------------------------------------------------------------------------- /apps/web/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import '../styles/globals.css'; 2 | import '@rainbow-me/rainbowkit/styles.css'; 3 | 4 | import * as React from 'react'; 5 | import { AppProps } from 'next/app'; 6 | import Head from 'next/head'; 7 | import { 8 | getDefaultWallets, 9 | RainbowKitProvider, 10 | } from '@rainbow-me/rainbowkit'; 11 | import { 12 | chain, 13 | configureChains, 14 | createClient, 15 | WagmiConfig, 16 | } from 'wagmi'; 17 | import { jsonRpcProvider } from 'wagmi/providers/jsonRpc'; 18 | import {ExampleCircuit} from 'foundry'; 19 | 20 | const {rpcUrl} = ExampleCircuit; 21 | 22 | const { chains, provider } = configureChains( 23 | [chain.localhost], 24 | [ 25 | jsonRpcProvider({ 26 | rpc: () => ({http: rpcUrl}), 27 | }) 28 | ] 29 | ); 30 | 31 | const {connectors} = getDefaultWallets({ 32 | appName: 'zk-starter', 33 | chains 34 | }); 35 | 36 | const wagmiClient = createClient({ 37 | autoConnect: false, 38 | connectors, 39 | provider 40 | }) 41 | 42 | export default function MyApp({ Component, pageProps }: AppProps): JSX.Element { 43 | return ( 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | ); 53 | } -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | workflow_dispatch: 5 | pull_request: 6 | push: 7 | branches: 8 | - master 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | 16 | - name: Install Foundry 17 | uses: onbjerg/foundry-toolchain@v1 18 | with: 19 | version: nightly 20 | 21 | - name: Install dependencies 22 | run: forge install 23 | 24 | - name: Check backward compatibility 25 | run: | 26 | forge build --skip test --use solc:0.8.0 27 | forge build --skip test --use solc:0.7.6 28 | forge build --skip test --use solc:0.7.0 29 | forge build --skip test --use solc:0.6.2 30 | 31 | test: 32 | runs-on: ubuntu-latest 33 | steps: 34 | - uses: actions/checkout@v3 35 | 36 | - name: Install Foundry 37 | uses: onbjerg/foundry-toolchain@v1 38 | with: 39 | version: nightly 40 | 41 | - name: Install dependencies 42 | run: forge install 43 | 44 | - name: Run tests 45 | run: forge test -vvv 46 | 47 | fmt: 48 | runs-on: ubuntu-latest 49 | steps: 50 | - uses: actions/checkout@v3 51 | 52 | - name: Install Foundry 53 | uses: onbjerg/foundry-toolchain@v1 54 | with: 55 | version: nightly 56 | 57 | - name: Check formatting 58 | run: forge fmt --check 59 | -------------------------------------------------------------------------------- /apps/web/README.md: -------------------------------------------------------------------------------- 1 | ## Getting Started 2 | 3 | First, run the development server: 4 | 5 | ```bash 6 | yarn dev 7 | ``` 8 | 9 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 10 | 11 | You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file. 12 | 13 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`. 14 | 15 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. 16 | 17 | ## Learn More 18 | 19 | To learn more about Next.js, take a look at the following resources: 20 | 21 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 22 | - [Learn Next.js](https://nextjs.org/learn/foundations/about-nextjs) - an interactive Next.js tutorial. 23 | 24 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 25 | 26 | ## Deploy on Vercel 27 | 28 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_source=github.com&utm_medium=referral&utm_campaign=turborepo-readme) from the creators of Next.js. 29 | 30 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 31 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/src/StdMath.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | library stdMath { 5 | int256 private constant INT256_MIN = -57896044618658097711785492504343953926634992332820282019728792003956564819968; 6 | 7 | function abs(int256 a) internal pure returns (uint256) { 8 | // Required or it will fail when `a = type(int256).min` 9 | if (a == INT256_MIN) { 10 | return 57896044618658097711785492504343953926634992332820282019728792003956564819968; 11 | } 12 | 13 | return uint256(a > 0 ? a : -a); 14 | } 15 | 16 | function delta(uint256 a, uint256 b) internal pure returns (uint256) { 17 | return a > b ? a - b : b - a; 18 | } 19 | 20 | function delta(int256 a, int256 b) internal pure returns (uint256) { 21 | // a and b are of the same sign 22 | // this works thanks to two's complement, the left-most bit is the sign bit 23 | if ((a ^ b) > -1) { 24 | return delta(abs(a), abs(b)); 25 | } 26 | 27 | // a and b are of opposite signs 28 | return abs(a) + abs(b); 29 | } 30 | 31 | function percentDelta(uint256 a, uint256 b) internal pure returns (uint256) { 32 | uint256 absDelta = delta(a, b); 33 | 34 | return absDelta * 1e18 / b; 35 | } 36 | 37 | function percentDelta(int256 a, int256 b) internal pure returns (uint256) { 38 | uint256 absDelta = delta(a, b); 39 | uint256 absB = abs(b); 40 | 41 | return absDelta * 1e18 / absB; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /scripts/ptau.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | # -------------------------------------------------------------------------------- 5 | # Phase 1 6 | # ... non-circuit-specific stuff 7 | 8 | # Starts Powers Of Tau ceremony, creating the file pot15_0000.ptau 9 | yarn snarkjs powersoftau new bn128 15 build/pot15_0000.ptau -v 10 | 11 | # Contribute to ceremony a few times... 12 | # As we want this to be non-interactive we'll just write something random-ish for entropy 13 | yarn snarkjs powersoftau contribute build/pot15_0000.ptau build/pot15_0001.ptau \ 14 | --name="First contribution" -v -e="$(head -n 4096 /dev/urandom | openssl sha1)" 15 | yarn snarkjs powersoftau contribute build/pot15_0001.ptau build/pot15_0002.ptau \ 16 | --name="Second contribution" -v -e="$(head -n 4096 /dev/urandom | openssl sha1)" 17 | yarn snarkjs powersoftau contribute build/pot15_0002.ptau build/pot15_0003.ptau \ 18 | --name="Third contribution" -v -e="$(head -n 4096 /dev/urandom | openssl sha1)" 19 | 20 | # Verify 21 | yarn snarkjs powersoftau verify build/pot15_0003.ptau 22 | 23 | # Apply random beacon to finalised this phase of the setup. 24 | # For more information about random beacons see here: https://eprint.iacr.org/2017/1050.pdf 25 | # For the purposes, the beacon is essentially a delayed hash function evaluated on 0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f 26 | # (in practice this value will be some form of high entropy and publicly available data of your choice) 27 | yarn snarkjs powersoftau beacon build/pot15_0003.ptau build/pot15_beacon.ptau \ 28 | 0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f 10 -n="Final Beacon" 29 | 30 | # Prepare phase 2... 31 | # Under the hood, the prepare phase2 command calculates the encrypted evaluation of the Lagrange polynomials at tau for 32 | # tau, alpha*tau and beta*tau. It takes the beacon ptau file we generated in the previous step, and outputs a final pta 33 | # file which will be used to generate the circuit proving and verification keys. 34 | yarn snarkjs powersoftau prepare phase2 build/pot15_beacon.ptau build/pot15_final.ptau -v 35 | 36 | # Verify the final ptau file. Creates the file pot15_final.ptau 37 | yarn snarkjs powersoftau verify build/pot15_final.ptau -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/src/interfaces/IERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.6.2; 2 | 3 | /// @dev Interface of the ERC20 standard as defined in the EIP. 4 | /// @dev This includes the optional name, symbol, and decimals metadata. 5 | interface IERC20 { 6 | /// @dev Emitted when `value` tokens are moved from one account (`from`) to another (`to`). 7 | event Transfer(address indexed from, address indexed to, uint256 value); 8 | 9 | /// @dev Emitted when the allowance of a `spender` for an `owner` is set, where `value` 10 | /// is the new allowance. 11 | event Approval(address indexed owner, address indexed spender, uint256 value); 12 | 13 | /// @notice Returns the amount of tokens in existence. 14 | function totalSupply() external view returns (uint256); 15 | 16 | /// @notice Returns the amount of tokens owned by `account`. 17 | function balanceOf(address account) external view returns (uint256); 18 | 19 | /// @notice Moves `amount` tokens from the caller's account to `to`. 20 | function transfer(address to, uint256 amount) external returns (bool); 21 | 22 | /// @notice Returns the remaining number of tokens that `spender` is allowed 23 | /// to spend on behalf of `owner` 24 | function allowance(address owner, address spender) external view returns (uint256); 25 | 26 | /// @notice Sets `amount` as the allowance of `spender` over the caller's tokens. 27 | /// @dev Be aware of front-running risks: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 28 | function approve(address spender, uint256 amount) external returns (bool); 29 | 30 | /// @notice Moves `amount` tokens from `from` to `to` using the allowance mechanism. 31 | /// `amount` is then deducted from the caller's allowance. 32 | function transferFrom(address from, address to, uint256 amount) external returns (bool); 33 | 34 | /// @notice Returns the name of the token. 35 | function name() external view returns (string memory); 36 | 37 | /// @notice Returns the symbol of the token. 38 | function symbol() external view returns (string memory); 39 | 40 | /// @notice Returns the decimals places of the token. 41 | function decimals() external view returns (uint8); 42 | } 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `zk-starter` 2 | 3 | The easiest way to integrate succinct verifiable on-chain computation using hidden information in custom applications that execute on a credibly-neutral immutable public ledger. 4 | 5 | Essentially, it's [__zero knowledge__](https://en.wikipedia.org/wiki/Zero-knowledge_proof) for those with zero knowledge. 6 | 7 | ### 🚀 Getting Started 8 | 9 | 1. Clone the repository using `git clone https://github.com/cawfree/zk-starter`. 10 | 2. Make sure you've installed [__Rust__](https://www.rust-lang.org/) and [__Foundry__](https://github.com/foundry-rs/foundry): 11 | 12 | ```shell 13 | curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh # install rust 14 | curl -L https://foundry.paradigm.xyz | bash # install foundry 15 | ``` 16 | 3. Run `yarn`, which will install [`circom`](https://docs.circom.io/) and automate a new [__Powers of Tau__](https://zkproof.org/2021/06/30/setup-ceremonies/#:~:text=The%20first%20phase%20referred%20to,NP%2Drelation%2Dspecific%20CRS.) ceremony, then finally compile your arithmetic circuits. When you make changes to your circuits, you can also use `yarn` to recompile them alongside their dependent smart contracts. 17 | 18 | > 💡 All the build artifacts are cached, so you'll only be required to do this once-per-installation. 19 | 20 | > ⚠️ By default, `zk-starter` is configured not to track the results of ceremonies. You can delete the ignore flag of the `build/` directory within the [`.gitignore`](.gitignore) to avoid data loss. 21 | 22 | 4. Finally, run `yarn dev` to execute the entire stack on [`http://localhost:3000`](http://localhost:3000). This will redeploy the auto-generated [__verifier logic__](https://docs.circom.io/getting-started/proving-circuits/) made available to your [__smart contracts__](https://ethereum.org/en/developers/docs/smart-contracts/) on the [`anvil`](https://github.com/foundry-rs/foundry) local chain and inject the relevant configuration properties into your frontend. 23 | 24 | ### ♻️ Adding New Circuits 25 | 26 | `zk-starter`'s build life cycle ensures that for each new arithmetic circuit you build, a corresponding [__Solidity__](https://docs.soliditylang.org/en/v0.8.17/) smart contract which inherits a compatible verifier will also be initialized for you to extend. 27 | 28 | Likewise, for each circuit you create, a matching utility library is provided to the applicaton frontend at compile time. This yields namespaced high-level functions for generating and verifying proofs, and abstracting away the complexity of smart contract invocation for on-chain verification. 29 | 30 | ### 🙏 Attribution 31 | 32 | This monorepo was inspired by [__BattleZips 🏴‍☠️__](https://twitter.com/Battlezips) ([__Git__](https://github.com/BattleZips/BattleZips)). Thank you for helping increase accessibility to the state-of-the-art in modern cryptography. 33 | 34 | ### ✌️ License 35 | [__MIT__](./LICENSE) 36 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/src/StdJson.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.0 <0.9.0; 3 | 4 | pragma experimental ABIEncoderV2; 5 | 6 | import "./Vm.sol"; 7 | 8 | // Helpers for parsing keys into types. 9 | library stdJson { 10 | VmSafe private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); 11 | 12 | function parseRaw(string memory json, string memory key) internal returns (bytes memory) { 13 | return vm.parseJson(json, key); 14 | } 15 | 16 | function readUint(string memory json, string memory key) internal returns (uint256) { 17 | return abi.decode(vm.parseJson(json, key), (uint256)); 18 | } 19 | 20 | function readUintArray(string memory json, string memory key) internal returns (uint256[] memory) { 21 | return abi.decode(vm.parseJson(json, key), (uint256[])); 22 | } 23 | 24 | function readInt(string memory json, string memory key) internal returns (int256) { 25 | return abi.decode(vm.parseJson(json, key), (int256)); 26 | } 27 | 28 | function readIntArray(string memory json, string memory key) internal returns (int256[] memory) { 29 | return abi.decode(vm.parseJson(json, key), (int256[])); 30 | } 31 | 32 | function readBytes32(string memory json, string memory key) internal returns (bytes32) { 33 | return abi.decode(vm.parseJson(json, key), (bytes32)); 34 | } 35 | 36 | function readBytes32Array(string memory json, string memory key) internal returns (bytes32[] memory) { 37 | return abi.decode(vm.parseJson(json, key), (bytes32[])); 38 | } 39 | 40 | function readString(string memory json, string memory key) internal returns (string memory) { 41 | return abi.decode(vm.parseJson(json, key), (string)); 42 | } 43 | 44 | function readStringArray(string memory json, string memory key) internal returns (string[] memory) { 45 | return abi.decode(vm.parseJson(json, key), (string[])); 46 | } 47 | 48 | function readAddress(string memory json, string memory key) internal returns (address) { 49 | return abi.decode(vm.parseJson(json, key), (address)); 50 | } 51 | 52 | function readAddressArray(string memory json, string memory key) internal returns (address[] memory) { 53 | return abi.decode(vm.parseJson(json, key), (address[])); 54 | } 55 | 56 | function readBool(string memory json, string memory key) internal returns (bool) { 57 | return abi.decode(vm.parseJson(json, key), (bool)); 58 | } 59 | 60 | function readBoolArray(string memory json, string memory key) internal returns (bool[] memory) { 61 | return abi.decode(vm.parseJson(json, key), (bool[])); 62 | } 63 | 64 | function readBytes(string memory json, string memory key) internal returns (bytes memory) { 65 | return abi.decode(vm.parseJson(json, key), (bytes)); 66 | } 67 | 68 | function readBytesArray(string memory json, string memory key) internal returns (bytes[] memory) { 69 | return abi.decode(vm.parseJson(json, key), (bytes[])); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/test/StdError.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0 <0.9.0; 3 | 4 | import "../src/StdError.sol"; 5 | import "../src/Test.sol"; 6 | 7 | contract StdErrorsTest is Test { 8 | ErrorsTest test; 9 | 10 | function setUp() public { 11 | test = new ErrorsTest(); 12 | } 13 | 14 | function testExpectAssertion() public { 15 | vm.expectRevert(stdError.assertionError); 16 | test.assertionError(); 17 | } 18 | 19 | function testExpectArithmetic() public { 20 | vm.expectRevert(stdError.arithmeticError); 21 | test.arithmeticError(10); 22 | } 23 | 24 | function testExpectDiv() public { 25 | vm.expectRevert(stdError.divisionError); 26 | test.divError(0); 27 | } 28 | 29 | function testExpectMod() public { 30 | vm.expectRevert(stdError.divisionError); 31 | test.modError(0); 32 | } 33 | 34 | function testExpectEnum() public { 35 | vm.expectRevert(stdError.enumConversionError); 36 | test.enumConversion(1); 37 | } 38 | 39 | function testExpectEncodeStg() public { 40 | vm.expectRevert(stdError.encodeStorageError); 41 | test.encodeStgError(); 42 | } 43 | 44 | function testExpectPop() public { 45 | vm.expectRevert(stdError.popError); 46 | test.pop(); 47 | } 48 | 49 | function testExpectOOB() public { 50 | vm.expectRevert(stdError.indexOOBError); 51 | test.indexOOBError(1); 52 | } 53 | 54 | function testExpectMem() public { 55 | vm.expectRevert(stdError.memOverflowError); 56 | test.mem(); 57 | } 58 | 59 | function testExpectIntern() public { 60 | vm.expectRevert(stdError.zeroVarError); 61 | test.intern(); 62 | } 63 | } 64 | 65 | contract ErrorsTest { 66 | enum T {T1} 67 | 68 | uint256[] public someArr; 69 | bytes someBytes; 70 | 71 | function assertionError() public pure { 72 | assert(false); 73 | } 74 | 75 | function arithmeticError(uint256 a) public pure { 76 | a -= 100; 77 | } 78 | 79 | function divError(uint256 a) public pure { 80 | 100 / a; 81 | } 82 | 83 | function modError(uint256 a) public pure { 84 | 100 % a; 85 | } 86 | 87 | function enumConversion(uint256 a) public pure { 88 | T(a); 89 | } 90 | 91 | function encodeStgError() public { 92 | /// @solidity memory-safe-assembly 93 | assembly { 94 | sstore(someBytes.slot, 1) 95 | } 96 | keccak256(someBytes); 97 | } 98 | 99 | function pop() public { 100 | someArr.pop(); 101 | } 102 | 103 | function indexOOBError(uint256 a) public pure { 104 | uint256[] memory t = new uint256[](0); 105 | t[a]; 106 | } 107 | 108 | function mem() public pure { 109 | uint256 l = 2 ** 256 / 32; 110 | new uint256[](l); 111 | } 112 | 113 | function intern() public returns (uint256) { 114 | function(uint256) internal returns (uint256) x; 115 | x(2); 116 | return 7; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /apps/web/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import {ExampleCircuit} from 'foundry'; 3 | 4 | import {ethers} from 'ethers'; 5 | import {ConnectButton} from '@rainbow-me/rainbowkit'; 6 | import {useAccount, useProvider, useSigner} from "wagmi"; 7 | 8 | const { 9 | contractAddress, 10 | abi, 11 | deployEtherFromFaucet, 12 | createZeroKnowledgeHelpersAsync, 13 | } = ExampleCircuit; 14 | 15 | type Result = { 16 | readonly successfullyVerifiedLocally: boolean; 17 | readonly successfullyVerifiedOnChain: boolean; 18 | }; 19 | 20 | export default function App(): JSX.Element { 21 | 22 | const {isConnected} = useAccount(); 23 | const provider = useProvider(); 24 | const {data: signer} = useSigner(); 25 | const [result, setResult] = React.useState(null); 26 | 27 | const onAttemptVerify = React.useCallback(() => void (async () => { 28 | 29 | if (!signer) throw new Error(`Expected signer, found "${String(signer)}".`); 30 | 31 | const signerAddress = await signer.getAddress(); 32 | 33 | // Give the wallet a little ether from the master wallet for the transaction. 34 | await deployEtherFromFaucet({to: signerAddress, provider}); 35 | 36 | const contract = new ethers.Contract(contractAddress, abi, signer); 37 | const currentSignerBalance = ethers.utils.formatEther(await provider.getBalance(signerAddress)); 38 | 39 | console.log({currentSignerBalance}); 40 | 41 | const {createProofAndPublicSignals} = await createZeroKnowledgeHelpersAsync(); 42 | const {checkIsProofValid, exportSolidityCallData} = await createProofAndPublicSignals({ 43 | inputSignals: {a: 3, b: 11}, 44 | }); 45 | 46 | const isValidLocal = await checkIsProofValid(); 47 | console.log({isValidLocal}); 48 | 49 | const isValidEthereum = await contract.verifyProof(...(await exportSolidityCallData())); 50 | 51 | console.log({isValidEthereum}); 52 | 53 | setResult({ 54 | successfullyVerifiedLocally: isValidLocal, 55 | successfullyVerifiedOnChain: isValidEthereum, 56 | }); 57 | })(), [provider, signer, setResult]); 58 | 59 | return ( 60 |
61 | 62 |
63 |
64 |

Welcome to zk-starter! 👋

65 |

66 | We can use adversarial incentivised networks like Ethereum to perform computation with very strong guarantees of correctness, immutability and verifiability. 67 |

68 |

69 | Although the security and resilience of public blockchains are indeed thanks to their open nature, humans nonetheless have a fundamental right to privacy. Similarly, increasing competition for block space and the subsequent rise in gas fees demand that we move more computation and storage off-chain, without compromising on our stringent operational expectations. 70 |

71 |

72 | A zero knowledge proof is a goldilocks paradigm, an inexplicable feature of the mathematics of the universe which helps us all operate privately, securely, trustlessly, minimally, with integrity; and above all else, in plain sight. 73 |

74 | {isConnected && ( 75 | 80 | )} 81 | {!!result && ( 82 | <> 83 |

84 | Verified within browser: {result.successfullyVerifiedLocally ? '✅' : '❌'} 85 |

86 |

87 | Verified on chain: {result.successfullyVerifiedOnChain ? '✅' : '❌'} 88 |

89 | 90 | )} 91 |
92 |
93 |
94 | ); 95 | } 96 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/test/StdUtils.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.7.0 <0.9.0; 3 | 4 | import "../src/Test.sol"; 5 | 6 | contract StdUtilsTest is Test { 7 | function testBound() public { 8 | assertEq(bound(5, 0, 4), 0); 9 | assertEq(bound(0, 69, 69), 69); 10 | assertEq(bound(0, 68, 69), 68); 11 | assertEq(bound(10, 150, 190), 174); 12 | assertEq(bound(300, 2800, 3200), 3107); 13 | assertEq(bound(9999, 1337, 6666), 4669); 14 | } 15 | 16 | function testBound_WithinRange() public { 17 | assertEq(bound(51, 50, 150), 51); 18 | assertEq(bound(51, 50, 150), bound(bound(51, 50, 150), 50, 150)); 19 | assertEq(bound(149, 50, 150), 149); 20 | assertEq(bound(149, 50, 150), bound(bound(149, 50, 150), 50, 150)); 21 | } 22 | 23 | function testBound_EdgeCoverage() public { 24 | assertEq(bound(0, 50, 150), 50); 25 | assertEq(bound(1, 50, 150), 51); 26 | assertEq(bound(2, 50, 150), 52); 27 | assertEq(bound(3, 50, 150), 53); 28 | assertEq(bound(type(uint256).max, 50, 150), 150); 29 | assertEq(bound(type(uint256).max - 1, 50, 150), 149); 30 | assertEq(bound(type(uint256).max - 2, 50, 150), 148); 31 | assertEq(bound(type(uint256).max - 3, 50, 150), 147); 32 | } 33 | 34 | function testBound_DistributionIsEven(uint256 min, uint256 size) public { 35 | size = size % 100 + 1; 36 | min = bound(min, UINT256_MAX / 2, UINT256_MAX / 2 + size); 37 | uint256 max = min + size - 1; 38 | uint256 result; 39 | 40 | for (uint256 i = 1; i <= size * 4; ++i) { 41 | // x > max 42 | result = bound(max + i, min, max); 43 | assertEq(result, min + (i - 1) % size); 44 | // x < min 45 | result = bound(min - i, min, max); 46 | assertEq(result, max - (i - 1) % size); 47 | } 48 | } 49 | 50 | function testBound(uint256 num, uint256 min, uint256 max) public { 51 | if (min > max) (min, max) = (max, min); 52 | 53 | uint256 result = bound(num, min, max); 54 | 55 | assertGe(result, min); 56 | assertLe(result, max); 57 | assertEq(result, bound(result, min, max)); 58 | if (num >= min && num <= max) assertEq(result, num); 59 | } 60 | 61 | function testBoundUint256Max() public { 62 | assertEq(bound(0, type(uint256).max - 1, type(uint256).max), type(uint256).max - 1); 63 | assertEq(bound(1, type(uint256).max - 1, type(uint256).max), type(uint256).max); 64 | } 65 | 66 | function testCannotBoundMaxLessThanMin() public { 67 | vm.expectRevert(bytes("StdUtils bound(uint256,uint256,uint256): Max is less than min.")); 68 | bound(5, 100, 10); 69 | } 70 | 71 | function testCannotBoundMaxLessThanMin(uint256 num, uint256 min, uint256 max) public { 72 | vm.assume(min > max); 73 | vm.expectRevert(bytes("StdUtils bound(uint256,uint256,uint256): Max is less than min.")); 74 | bound(num, min, max); 75 | } 76 | 77 | function testGenerateCreateAddress() external { 78 | address deployer = 0x6C9FC64A53c1b71FB3f9Af64d1ae3A4931A5f4E9; 79 | uint256 nonce = 14; 80 | address createAddress = computeCreateAddress(deployer, nonce); 81 | assertEq(createAddress, 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45); 82 | } 83 | 84 | function testGenerateCreate2Address() external { 85 | bytes32 salt = bytes32(uint256(31415)); 86 | bytes32 initcodeHash = keccak256(abi.encode(0x6080)); 87 | address deployer = 0x6C9FC64A53c1b71FB3f9Af64d1ae3A4931A5f4E9; 88 | address create2Address = computeCreate2Address(salt, initcodeHash, deployer); 89 | assertEq(create2Address, 0xB147a5d25748fda14b463EB04B111027C290f4d3); 90 | } 91 | 92 | function testAssumeNoPrecompilesL1(address addr) external { 93 | assumeNoPrecompiles(addr, stdChains.Mainnet.chainId); 94 | assertTrue(addr < address(1) || addr > address(9)); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/src/StdUtils.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | import "./console2.sol"; 5 | 6 | abstract contract StdUtils { 7 | uint256 private constant UINT256_MAX = 8 | 115792089237316195423570985008687907853269984665640564039457584007913129639935; 9 | 10 | function _bound(uint256 x, uint256 min, uint256 max) internal pure virtual returns (uint256 result) { 11 | require(min <= max, "StdUtils bound(uint256,uint256,uint256): Max is less than min."); 12 | 13 | // If x is between min and max, return x directly. This is to ensure that dictionary values 14 | // do not get shifted if the min is nonzero. More info: https://github.com/foundry-rs/forge-std/issues/188 15 | if (x >= min && x <= max) return x; 16 | 17 | uint256 size = max - min + 1; 18 | 19 | // If the value is 0, 1, 2, 3, warp that to min, min+1, min+2, min+3. Similarly for the UINT256_MAX side. 20 | // This helps ensure coverage of the min/max values. 21 | if (x <= 3 && size > x) return min + x; 22 | if (x >= UINT256_MAX - 3 && size > UINT256_MAX - x) return max - (UINT256_MAX - x); 23 | 24 | // Otherwise, wrap x into the range [min, max], i.e. the range is inclusive. 25 | if (x > max) { 26 | uint256 diff = x - max; 27 | uint256 rem = diff % size; 28 | if (rem == 0) return max; 29 | result = min + rem - 1; 30 | } else if (x < max) { 31 | uint256 diff = min - x; 32 | uint256 rem = diff % size; 33 | if (rem == 0) return min; 34 | result = max - rem + 1; 35 | } 36 | } 37 | 38 | function bound(uint256 x, uint256 min, uint256 max) internal view virtual returns (uint256 result) { 39 | result = _bound(x, min, max); 40 | console2.log("Bound Result", result); 41 | } 42 | 43 | /// @dev Compute the address a contract will be deployed at for a given deployer address and nonce 44 | /// @notice adapated from Solmate implementation (https://github.com/Rari-Capital/solmate/blob/main/src/utils/LibRLP.sol) 45 | function computeCreateAddress(address deployer, uint256 nonce) internal pure virtual returns (address) { 46 | // forgefmt: disable-start 47 | // The integer zero is treated as an empty byte string, and as a result it only has a length prefix, 0x80, computed via 0x80 + 0. 48 | // A one byte integer uses its own value as its length prefix, there is no additional "0x80 + length" prefix that comes before it. 49 | if (nonce == 0x00) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), deployer, bytes1(0x80)))); 50 | if (nonce <= 0x7f) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), deployer, uint8(nonce)))); 51 | 52 | // Nonces greater than 1 byte all follow a consistent encoding scheme, where each value is preceded by a prefix of 0x80 + length. 53 | if (nonce <= 2**8 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd7), bytes1(0x94), deployer, bytes1(0x81), uint8(nonce)))); 54 | if (nonce <= 2**16 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd8), bytes1(0x94), deployer, bytes1(0x82), uint16(nonce)))); 55 | if (nonce <= 2**24 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd9), bytes1(0x94), deployer, bytes1(0x83), uint24(nonce)))); 56 | // forgefmt: disable-end 57 | 58 | // More details about RLP encoding can be found here: https://eth.wiki/fundamentals/rlp 59 | // 0xda = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ proxy ++ 0x84 ++ nonce) 60 | // 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex) 61 | // 0x84 = 0x80 + 0x04 (0x04 = the bytes length of the nonce, 4 bytes, in hex) 62 | // We assume nobody can have a nonce large enough to require more than 32 bytes. 63 | return addressFromLast20Bytes( 64 | keccak256(abi.encodePacked(bytes1(0xda), bytes1(0x94), deployer, bytes1(0x84), uint32(nonce))) 65 | ); 66 | } 67 | 68 | function computeCreate2Address(bytes32 salt, bytes32 initcodeHash, address deployer) 69 | internal 70 | pure 71 | virtual 72 | returns (address) 73 | { 74 | return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xff), deployer, salt, initcodeHash))); 75 | } 76 | 77 | function addressFromLast20Bytes(bytes32 bytesValue) private pure returns (address) { 78 | return address(uint160(uint256(bytesValue))); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /scripts/circuits.ts: -------------------------------------------------------------------------------- 1 | import * as child_process from 'child_process'; 2 | import * as fs from 'fs'; 3 | import * as path from 'path'; 4 | 5 | const ext = '.circom'; 6 | 7 | const foundry = path.resolve('packages', 'foundry'); 8 | 9 | const circuits = fs.readdirSync(path.resolve(foundry, 'circuits')) 10 | .filter(e => e.endsWith(ext)); 11 | 12 | const opts = {stdio: 'inherit'} as const; 13 | 14 | const publicDir = path.resolve('apps', 'web', 'public'); 15 | !fs.existsSync(publicDir) && fs.mkdirSync(publicDir); 16 | 17 | circuits.forEach((circuit: string) => { 18 | const name = circuit.substring(0, circuit.lastIndexOf(ext)); 19 | 20 | // Compile circuit. 21 | child_process.execSync( 22 | `circom ${path.resolve(foundry, 'circuits', circuit)} -o build/ --r1cs --wasm`, 23 | opts, 24 | ); 25 | 26 | // Setup. 27 | child_process.execSync( 28 | `yarn snarkjs groth16 setup build/${name}.r1cs build/pot15_final.ptau build/board_final.zkey`, 29 | opts, 30 | ); 31 | 32 | child_process.execSync( 33 | `yarn snarkjs zkey new build/${name}.r1cs build/pot15_final.ptau build/${name}_0000.zkey`, 34 | opts, 35 | ); 36 | 37 | // Ceremony similar to ptau, but for the circuit's zkey this time. Generate commits to the zkey with entropy. 38 | // Zkeys are intended to be hosted on IPFS, since the prover is required to encrypt their data passed into the wasm circuit. 39 | child_process.execSync( 40 | `yarn snarkjs zkey contribute build/${name}_0000.zkey build/${name}_0001.zkey --name="First ${name} contribution" -v -e="$(head -n 4096 /dev/urandom | openssl sha1)"`, 41 | opts, 42 | ); 43 | child_process.execSync( 44 | `yarn snarkjs zkey contribute build/${name}_0001.zkey build/${name}_0002.zkey --name="Second ${name} contribution" -v -e="$(head -n 4096 /dev/urandom | openssl sha1)"`, 45 | opts, 46 | ); 47 | child_process.execSync( 48 | `yarn snarkjs zkey contribute build/${name}_0002.zkey build/${name}_0003.zkey --name="Third ${name} contribution" -v -e="$(head -n 4096 /dev/urandom | openssl sha1)"`, 49 | opts, 50 | ); 51 | 52 | // Verify zkey. 53 | child_process.execSync( 54 | `yarn snarkjs zkey verify build/${name}.r1cs build/pot15_final.ptau build/${name}_0003.zkey`, 55 | opts, 56 | ); 57 | 58 | // Apply a random beacon. 59 | child_process.execSync( 60 | `yarn snarkjs zkey beacon build/${name}_0003.zkey build/${name}_final.zkey 0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f 10 -n="${name} FinalBeacon phase2"`, 61 | opts, 62 | ); 63 | 64 | // Optional: verify the final zkey. 65 | child_process.execSync( 66 | `yarn snarkjs zkey verify build/${name}.r1cs build/pot15_final.ptau build/${name}_final.zkey`, 67 | opts, 68 | ); 69 | 70 | // Export verification key. (Optional, but we can use this to check the proofs generated in the client prior to submission.) 71 | child_process.execSync( 72 | `yarn snarkjs zkey export verificationkey build/${name}_final.zkey build/${name}_verification_key.json`, 73 | opts, 74 | ); 75 | 76 | const scriptDir = path.resolve(foundry, 'script'); 77 | const testsDir = path.resolve(foundry, 'test'); 78 | const contractsDir = path.resolve(foundry, 'src'); 79 | const generatedContractsDir = path.resolve(contractsDir, 'generated'); 80 | 81 | if (!fs.existsSync(generatedContractsDir)) fs.mkdirSync(generatedContractsDir); 82 | 83 | // Export matching solidity verifier. 84 | child_process.execSync( 85 | `yarn snarkjs zkey export solidityverifier build/${name}_final.zkey ${path.resolve(generatedContractsDir, `${name}Verifier.sol`)}`, 86 | opts, 87 | ); 88 | 89 | // Update the solidity version for compatibility with nested arrays. 90 | child_process.execSync( 91 | `sed -i.bak "s/0.6.11/0.8.11/g" ${path.resolve(generatedContractsDir, `${name}Verifier.sol`)}`, 92 | opts, 93 | ); 94 | 95 | // Remove the backup. 96 | fs.unlinkSync(path.resolve(generatedContractsDir, `${name}Verifier.sol.bak`)); 97 | 98 | const smartContractForVerifier = path.resolve(contractsDir, `${name}.sol`); 99 | 100 | // TODO: Here we could create working tests for proofs, too... 101 | 102 | // Ensure there's a matching smart contract for this circuit. 103 | if (!fs.existsSync(smartContractForVerifier)) 104 | fs.writeFileSync( 105 | smartContractForVerifier, 106 | ` 107 | // SPDX-License-Identifier: UNLICENSED 108 | pragma solidity ^0.8.11; 109 | 110 | import "./generated/${name}Verifier.sol"; 111 | 112 | contract ${name} is Verifier {} 113 | `.trim(), 114 | ); 115 | 116 | const testForSmartContractForVerifier = path.resolve(testsDir, `${name}.t.sol`); 117 | 118 | // TODO: enforce that circuits are named with an uppercase letter 119 | 120 | if (!fs.existsSync(testForSmartContractForVerifier)) 121 | fs.writeFileSync( 122 | testForSmartContractForVerifier, 123 | ` 124 | // SPDX-License-Identifier: UNLICENSED 125 | pragma solidity ^0.8.11; 126 | 127 | import "forge-std/Test.sol"; 128 | 129 | import "../src/${name}.sol"; 130 | 131 | contract ${name}Test is Test { 132 | ${name} public ${name.toLowerCase()}; 133 | 134 | function setUp() public { 135 | ${name.toLowerCase()} = new ${name}(); 136 | } 137 | 138 | function testTestsAreInvokedFor${name}() public { 139 | assertEq(true, true); 140 | } 141 | 142 | } 143 | `.trim(), 144 | ); 145 | 146 | const deployScriptForSmartContractForVerifier = path.resolve(scriptDir, `${name}.s.sol`); 147 | 148 | if (!fs.existsSync(deployScriptForSmartContractForVerifier)) 149 | fs.writeFileSync( 150 | deployScriptForSmartContractForVerifier, 151 | ` 152 | // SPDX-License-Identifier: UNLICENSED 153 | pragma solidity ^0.8.11; 154 | 155 | import "forge-std/Script.sol"; 156 | 157 | contract ${name}Script is Script { 158 | function setUp() public {} 159 | 160 | function run() public { 161 | vm.broadcast(); 162 | } 163 | } 164 | `.trim(), 165 | ); 166 | 167 | child_process.execSync( 168 | `cp -rf ${path.resolve('build', `${name}_js`, `${name}.wasm`)} ${publicDir}/`, 169 | opts, 170 | ); 171 | 172 | child_process.execSync( 173 | `cp -rf ${path.resolve('build', `${name}_final.zkey`)} ${publicDir}/`, 174 | opts, 175 | ); 176 | 177 | child_process.execSync( 178 | `cp -rf ${path.resolve('build', `${name}_verification_key.json`)} ${publicDir}/`, 179 | opts, 180 | ); 181 | 182 | }); 183 | -------------------------------------------------------------------------------- /packages/foundry/scripts/dev.ts: -------------------------------------------------------------------------------- 1 | import * as child_process from 'child_process'; 2 | import * as path from 'path'; 3 | import * as fs from 'fs'; 4 | 5 | import {ethers} from 'ethers'; 6 | 7 | const ANVIL_DEFAULT_WALLET_PRIVATE_KEY_DO_NOT_USE_YOU_WILL_GET_REKT = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80'; 8 | 9 | const deployContractsByName = async ({contractNames, url}: { 10 | readonly contractNames: readonly string[]; 11 | readonly url: string; 12 | }) => { 13 | const provider = new ethers.providers.JsonRpcProvider(url); 14 | const wallet = new ethers.Wallet(ANVIL_DEFAULT_WALLET_PRIVATE_KEY_DO_NOT_USE_YOU_WILL_GET_REKT, provider); 15 | 16 | const contractNameToDeploymentAddress: Record = Object.fromEntries( 17 | await Promise.all( 18 | contractNames.map(async contractName => { 19 | const {abi, bytecode} = JSON.parse(fs.readFileSync( 20 | path.resolve('..', '..', 'packages', 'foundry', 'out', `${contractName}.sol`, `${contractName}.json`), 21 | 'utf-8' 22 | )); 23 | const {address} = await new ethers.ContractFactory(abi, bytecode, wallet).deploy(); 24 | return [contractName, address]; 25 | }) 26 | ), 27 | ); 28 | return {contractNameToDeploymentAddress}; 29 | }; 30 | 31 | const deployContractsAndWriteModule = async ({ 32 | contractNames, 33 | url, 34 | }: { 35 | readonly contractNames: readonly string[]; 36 | readonly url: string; 37 | }) => { 38 | 39 | const { 40 | contractNameToDeploymentAddress, 41 | } = await deployContractsByName({contractNames, url}); 42 | 43 | if (!fs.existsSync(path.resolve('dist'))) fs.mkdirSync('dist'); 44 | 45 | // TODO: create the package here 46 | fs.writeFileSync( 47 | path.resolve('dist', 'index.ts'), 48 | ` 49 | import {ethers, Wallet} from 'ethers'; 50 | import * as ffjavascript from 'ffjavascript'; 51 | 52 | const ANVIL_DEFAULT_WALLET_PRIVATE_KEY_DO_NOT_USE_YOU_WILL_GET_REKT = "${ANVIL_DEFAULT_WALLET_PRIVATE_KEY_DO_NOT_USE_YOU_WILL_GET_REKT}"; 53 | 54 | const deployEtherFromFaucet = async ({ 55 | to, 56 | provider, 57 | amount = ethers.utils.parseEther('1'), 58 | }: { 59 | readonly to: string; 60 | readonly provider: ethers.providers.Provider; 61 | readonly amount?: ethers.BigNumber; 62 | }) => { 63 | const wallet = new Wallet( 64 | ANVIL_DEFAULT_WALLET_PRIVATE_KEY_DO_NOT_USE_YOU_WILL_GET_REKT, 65 | provider, 66 | ); 67 | const signedTransaction = await wallet.signTransaction( 68 | await wallet.populateTransaction({ 69 | to, 70 | value: amount, 71 | chainId: (await provider.getNetwork()).chainId, 72 | }) 73 | ); 74 | return provider.sendTransaction(signedTransaction); 75 | }; 76 | 77 | ${contractNames 78 | .map( 79 | (contractName: string) => { 80 | const witnessCalculatorExport = fs.readFileSync( 81 | path.resolve('..', '..', 'build', `${contractName}_js`, 'witness_calculator.js'), 82 | 'utf-8', 83 | ); 84 | return [ 85 | `function ${contractName}WitnessCalculatorThunk() {`, 86 | ` ${witnessCalculatorExport.substring('module.exports = '.length)}`, 87 | ' return async () => {', 88 | ' const [wasm, verificationKey] = await Promise.all([', 89 | ` fetch(\'/${contractName}.wasm\').then(e => e.arrayBuffer()),`, 90 | ` fetch(\'/${contractName}_verification_key.json\').then(e => e.json()),`, 91 | ' ]);', 92 | ' // @ts-expect-error missing-parameter', 93 | ' const witnessCalculator = await builder(wasm);', 94 | ' const createProofAndPublicSignals = async ({inputSignals}: {readonly inputSignals: object}) => {', 95 | ' const witnessBuffer = await witnessCalculator.calculateWTNSBin(', 96 | ' inputSignals,', 97 | ' 0,', 98 | ' );', 99 | ' // @ts-expect-error global-script', 100 | ` const {proof, publicSignals} = await snarkjs.groth16.prove('\/${contractName}_final.zkey', witnessBuffer);`, 101 | ' // @ts-ignore', 102 | ' const {unstringifyBigInts} = ffjavascript.utils;', 103 | ' // @ts-ignore', 104 | ' const checkIsProofValid = (): Promise => snarkjs.groth16.verify(verificationKey, publicSignals, proof);', 105 | ' const exportSolidityCallData = async (): Promise => {', 106 | ' // https://gist.github.com/chnejohnson/c6d76ef15c108464539de535d48a7f9b', 107 | ' // @ts-ignore', 108 | ' const calldata = await snarkjs.groth16.exportSolidityCallData(', 109 | ' unstringifyBigInts(proof),', 110 | ' unstringifyBigInts(publicSignals),', 111 | ' );', 112 | ' return JSON.parse(`[${calldata}]`);', 113 | ' };', 114 | ' return {proof, publicSignals, checkIsProofValid, exportSolidityCallData};', 115 | ' };', 116 | ' return {createProofAndPublicSignals, verificationKey};', 117 | ' }', 118 | '}', 119 | ].join('\n'); 120 | }, 121 | ) 122 | .join('\n') 123 | } 124 | 125 | ${contractNames.map((contractName: string) => ` 126 | export const ${contractName} = Object.freeze({ 127 | ...${JSON.stringify(JSON.parse(fs.readFileSync( 128 | path.resolve('..', 'foundry', 'out', `${contractName}.sol`, `${contractName}.json`), 129 | 'utf-8', 130 | )))}, 131 | rpcUrl: "${url}", 132 | contractAddress: "${contractNameToDeploymentAddress[contractName]}", 133 | deployEtherFromFaucet, 134 | createZeroKnowledgeHelpersAsync: ${contractName}WitnessCalculatorThunk(), 135 | }); 136 | `.trim(), 137 | )} 138 | `.trim(), 139 | ); 140 | }; 141 | 142 | const pipe = ( 143 | child?: child_process.ChildProcess 144 | ) => { 145 | child?.stdout?.pipe(process.stdout); 146 | child?.stderr?.pipe(process.stderr); 147 | return child; 148 | }; 149 | 150 | child_process.execSync('forge build', {stdio: 'inherit'}); 151 | 152 | const contractNames = fs.readdirSync(path.resolve('circuits')) 153 | .filter(e => e.endsWith('.circom')) 154 | .map(e => e.substring(0, e.lastIndexOf('.circom'))); 155 | 156 | void (async () => Promise.all([ 157 | pipe(child_process.exec('anvil --chain-id 1337')), 158 | 159 | // Wait a little time to spin up the deployment. 160 | new Promise(resolve => setTimeout(resolve, 1000)) 161 | .then(() => deployContractsAndWriteModule({ 162 | contractNames, 163 | url: 'http://localhost:8545', 164 | })), 165 | ]))(); 166 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/src/interfaces/IERC1155.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.6.2; 2 | 3 | import "./IERC165.sol"; 4 | 5 | /// @title ERC-1155 Multi Token Standard 6 | /// @dev See https://eips.ethereum.org/EIPS/eip-1155 7 | /// Note: The ERC-165 identifier for this interface is 0xd9b67a26. 8 | interface ERC1155 is IERC165 { 9 | /// @dev 10 | /// - Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "Safe Transfer Rules" section of the standard). 11 | /// - The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender). 12 | /// - The `_from` argument MUST be the address of the holder whose balance is decreased. 13 | /// - The `_to` argument MUST be the address of the recipient whose balance is increased. 14 | /// - The `_id` argument MUST be the token type being transferred. 15 | /// - The `_value` argument MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by. 16 | /// - When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address). 17 | /// - When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address). 18 | event TransferSingle( 19 | address indexed _operator, address indexed _from, address indexed _to, uint256 _id, uint256 _value 20 | ); 21 | 22 | /// @dev 23 | /// - Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "Safe Transfer Rules" section of the standard). 24 | /// - The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender). 25 | /// - The `_from` argument MUST be the address of the holder whose balance is decreased. 26 | /// - The `_to` argument MUST be the address of the recipient whose balance is increased. 27 | /// - The `_ids` argument MUST be the list of tokens being transferred. 28 | /// - The `_values` argument MUST be the list of number of tokens (matching the list and order of tokens specified in _ids) the holder balance is decreased by and match what the recipient balance is increased by. 29 | /// - When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address). 30 | /// - When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address). 31 | event TransferBatch( 32 | address indexed _operator, address indexed _from, address indexed _to, uint256[] _ids, uint256[] _values 33 | ); 34 | 35 | /// @dev MUST emit when approval for a second party/operator address to manage all tokens for an owner address is enabled or disabled (absence of an event assumes disabled). 36 | event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved); 37 | 38 | /// @dev MUST emit when the URI is updated for a token ID. URIs are defined in RFC 3986. 39 | /// The URI MUST point to a JSON file that conforms to the "ERC-1155 Metadata URI JSON Schema". 40 | event URI(string _value, uint256 indexed _id); 41 | 42 | /// @notice Transfers `_value` amount of an `_id` from the `_from` address to the `_to` address specified (with safety call). 43 | /// @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard). 44 | /// - MUST revert if `_to` is the zero address. 45 | /// - MUST revert if balance of holder for token `_id` is lower than the `_value` sent. 46 | /// - MUST revert on any other error. 47 | /// - MUST emit the `TransferSingle` event to reflect the balance change (see "Safe Transfer Rules" section of the standard). 48 | /// - After the above conditions are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). 49 | /// @param _from Source address 50 | /// @param _to Target address 51 | /// @param _id ID of the token type 52 | /// @param _value Transfer amount 53 | /// @param _data Additional data with no specified format, MUST be sent unaltered in call to `onERC1155Received` on `_to` 54 | function safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes calldata _data) external; 55 | 56 | /// @notice Transfers `_values` amount(s) of `_ids` from the `_from` address to the `_to` address specified (with safety call). 57 | /// @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard). 58 | /// - MUST revert if `_to` is the zero address. 59 | /// - MUST revert if length of `_ids` is not the same as length of `_values`. 60 | /// - MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `_values` sent to the recipient. 61 | /// - MUST revert on any other error. 62 | /// - MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see "Safe Transfer Rules" section of the standard). 63 | /// - Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc). 64 | /// - After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). 65 | /// @param _from Source address 66 | /// @param _to Target address 67 | /// @param _ids IDs of each token type (order and length must match _values array) 68 | /// @param _values Transfer amounts per token type (order and length must match _ids array) 69 | /// @param _data Additional data with no specified format, MUST be sent unaltered in call to the `ERC1155TokenReceiver` hook(s) on `_to` 70 | function safeBatchTransferFrom( 71 | address _from, 72 | address _to, 73 | uint256[] calldata _ids, 74 | uint256[] calldata _values, 75 | bytes calldata _data 76 | ) external; 77 | 78 | /// @notice Get the balance of an account's tokens. 79 | /// @param _owner The address of the token holder 80 | /// @param _id ID of the token 81 | /// @return The _owner's balance of the token type requested 82 | function balanceOf(address _owner, uint256 _id) external view returns (uint256); 83 | 84 | /// @notice Get the balance of multiple account/token pairs 85 | /// @param _owners The addresses of the token holders 86 | /// @param _ids ID of the tokens 87 | /// @return The _owner's balance of the token types requested (i.e. balance for each (owner, id) pair) 88 | function balanceOfBatch(address[] calldata _owners, uint256[] calldata _ids) 89 | external 90 | view 91 | returns (uint256[] memory); 92 | 93 | /// @notice Enable or disable approval for a third party ("operator") to manage all of the caller's tokens. 94 | /// @dev MUST emit the ApprovalForAll event on success. 95 | /// @param _operator Address to add to the set of authorized operators 96 | /// @param _approved True if the operator is approved, false to revoke approval 97 | function setApprovalForAll(address _operator, bool _approved) external; 98 | 99 | /// @notice Queries the approval status of an operator for a given owner. 100 | /// @param _owner The owner of the tokens 101 | /// @param _operator Address of authorized operator 102 | /// @return True if the operator is approved, false if not 103 | function isApprovedForAll(address _owner, address _operator) external view returns (bool); 104 | } 105 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/lib/ds-test/demo/demo.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity >=0.5.0; 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 | emit log_named_uint("uint", 512); 16 | 17 | emit log("-- log_named_int(string, int)"); 18 | emit log_named_int("int", -512); 19 | 20 | emit log("-- log_named_address(string, address)"); 21 | emit log_named_address("address", address(this)); 22 | 23 | emit log("-- log_named_bytes32(string, bytes32)"); 24 | emit log_named_bytes32("bytes32", "a string"); 25 | 26 | emit log("-- log_named_bytes(string, bytes)"); 27 | emit log_named_bytes("bytes", hex"cafefe"); 28 | 29 | emit log("-- log_named_string(string, string)"); 30 | emit log_named_string("string", "a string"); 31 | 32 | emit log("-- log_named_decimal_uint(string, uint, uint)"); 33 | emit log_named_decimal_uint("decimal uint", 1.0e18, 18); 34 | 35 | emit log("-- log_named_decimal_int(string, int, uint)"); 36 | emit 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 | emit log_old_named_uint("key", 500); 41 | emit 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\\nstring"); 48 | emit log("a multiline string"); 49 | emit log_bytes("a string"); 50 | emit log_bytes("a multiline\nstring"); 51 | emit log_bytes("a multiline\\nstring"); 52 | emit logs(hex"0000"); 53 | emit log_named_bytes("0x0000", hex"0000"); 54 | emit logs(hex"ff"); 55 | } 56 | function echo(string memory s1, string memory s2) public pure 57 | returns (string memory, string memory) 58 | { 59 | return (s1, s2); 60 | } 61 | 62 | function prove_this(uint x) public { 63 | emit log_named_uint("sym x", x); 64 | assertGt(x + 1, 0); 65 | } 66 | 67 | function test_logn() public { 68 | assembly { 69 | log0(0x01, 0x02) 70 | log1(0x01, 0x02, 0x03) 71 | log2(0x01, 0x02, 0x03, 0x04) 72 | log3(0x01, 0x02, 0x03, 0x04, 0x05) 73 | } 74 | } 75 | 76 | event MyEvent(uint, uint indexed, uint, uint indexed); 77 | function test_events() public { 78 | emit MyEvent(1, 2, 3, 4); 79 | } 80 | 81 | function test_asserts() public { 82 | string memory err = "this test has failed!"; 83 | emit log("## assertTrue(bool)\n"); 84 | assertTrue(false); 85 | emit log("\n"); 86 | assertTrue(false, err); 87 | 88 | emit log("\n## assertEq(address,address)\n"); 89 | assertEq(address(this), msg.sender); 90 | emit log("\n"); 91 | assertEq(address(this), msg.sender, err); 92 | 93 | emit log("\n## assertEq32(bytes32,bytes32)\n"); 94 | assertEq32("bytes 1", "bytes 2"); 95 | emit log("\n"); 96 | assertEq32("bytes 1", "bytes 2", err); 97 | 98 | emit log("\n## assertEq(bytes32,bytes32)\n"); 99 | assertEq32("bytes 1", "bytes 2"); 100 | emit log("\n"); 101 | assertEq32("bytes 1", "bytes 2", err); 102 | 103 | emit log("\n## assertEq(uint,uint)\n"); 104 | assertEq(uint(0), 1); 105 | emit log("\n"); 106 | assertEq(uint(0), 1, err); 107 | 108 | emit log("\n## assertEq(int,int)\n"); 109 | assertEq(-1, -2); 110 | emit log("\n"); 111 | assertEq(-1, -2, err); 112 | 113 | emit log("\n## assertEqDecimal(int,int,uint)\n"); 114 | assertEqDecimal(-1.0e18, -1.1e18, 18); 115 | emit log("\n"); 116 | assertEqDecimal(-1.0e18, -1.1e18, 18, err); 117 | 118 | emit log("\n## assertEqDecimal(uint,uint,uint)\n"); 119 | assertEqDecimal(uint(1.0e18), 1.1e18, 18); 120 | emit log("\n"); 121 | assertEqDecimal(uint(1.0e18), 1.1e18, 18, err); 122 | 123 | emit log("\n## assertGt(uint,uint)\n"); 124 | assertGt(uint(0), 0); 125 | emit log("\n"); 126 | assertGt(uint(0), 0, err); 127 | 128 | emit log("\n## assertGt(int,int)\n"); 129 | assertGt(-1, -1); 130 | emit log("\n"); 131 | assertGt(-1, -1, err); 132 | 133 | emit log("\n## assertGtDecimal(int,int,uint)\n"); 134 | assertGtDecimal(-2.0e18, -1.1e18, 18); 135 | emit log("\n"); 136 | assertGtDecimal(-2.0e18, -1.1e18, 18, err); 137 | 138 | emit log("\n## assertGtDecimal(uint,uint,uint)\n"); 139 | assertGtDecimal(uint(1.0e18), 1.1e18, 18); 140 | emit log("\n"); 141 | assertGtDecimal(uint(1.0e18), 1.1e18, 18, err); 142 | 143 | emit log("\n## assertGe(uint,uint)\n"); 144 | assertGe(uint(0), 1); 145 | emit log("\n"); 146 | assertGe(uint(0), 1, err); 147 | 148 | emit log("\n## assertGe(int,int)\n"); 149 | assertGe(-1, 0); 150 | emit log("\n"); 151 | assertGe(-1, 0, err); 152 | 153 | emit log("\n## assertGeDecimal(int,int,uint)\n"); 154 | assertGeDecimal(-2.0e18, -1.1e18, 18); 155 | emit log("\n"); 156 | assertGeDecimal(-2.0e18, -1.1e18, 18, err); 157 | 158 | emit log("\n## assertGeDecimal(uint,uint,uint)\n"); 159 | assertGeDecimal(uint(1.0e18), 1.1e18, 18); 160 | emit log("\n"); 161 | assertGeDecimal(uint(1.0e18), 1.1e18, 18, err); 162 | 163 | emit log("\n## assertLt(uint,uint)\n"); 164 | assertLt(uint(0), 0); 165 | emit log("\n"); 166 | assertLt(uint(0), 0, err); 167 | 168 | emit log("\n## assertLt(int,int)\n"); 169 | assertLt(-1, -1); 170 | emit log("\n"); 171 | assertLt(-1, -1, err); 172 | 173 | emit log("\n## assertLtDecimal(int,int,uint)\n"); 174 | assertLtDecimal(-1.0e18, -1.1e18, 18); 175 | emit log("\n"); 176 | assertLtDecimal(-1.0e18, -1.1e18, 18, err); 177 | 178 | emit log("\n## assertLtDecimal(uint,uint,uint)\n"); 179 | assertLtDecimal(uint(2.0e18), 1.1e18, 18); 180 | emit log("\n"); 181 | assertLtDecimal(uint(2.0e18), 1.1e18, 18, err); 182 | 183 | emit log("\n## assertLe(uint,uint)\n"); 184 | assertLe(uint(1), 0); 185 | emit log("\n"); 186 | assertLe(uint(1), 0, err); 187 | 188 | emit log("\n## assertLe(int,int)\n"); 189 | assertLe(0, -1); 190 | emit log("\n"); 191 | assertLe(0, -1, err); 192 | 193 | emit log("\n## assertLeDecimal(int,int,uint)\n"); 194 | assertLeDecimal(-1.0e18, -1.1e18, 18); 195 | emit log("\n"); 196 | assertLeDecimal(-1.0e18, -1.1e18, 18, err); 197 | 198 | emit log("\n## assertLeDecimal(uint,uint,uint)\n"); 199 | assertLeDecimal(uint(2.0e18), 1.1e18, 18); 200 | emit log("\n"); 201 | assertLeDecimal(uint(2.0e18), 1.1e18, 18, err); 202 | 203 | emit log("\n## assertEq(string,string)\n"); 204 | string memory s1 = "string 1"; 205 | string memory s2 = "string 2"; 206 | assertEq(s1, s2); 207 | emit log("\n"); 208 | assertEq(s1, s2, err); 209 | 210 | emit log("\n## assertEq0(bytes,bytes)\n"); 211 | assertEq0(hex"abcdef01", hex"abcdef02"); 212 | emit log("\n"); 213 | assertEq0(hex"abcdef01", hex"abcdef02", err); 214 | } 215 | } 216 | 217 | contract DemoTestWithSetUp { 218 | function setUp() public { 219 | } 220 | function test_pass() public pure { 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/src/StdAssertions.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | import "../lib/ds-test/src/test.sol"; 5 | import "./StdMath.sol"; 6 | 7 | abstract contract StdAssertions is DSTest { 8 | event log_array(uint256[] val); 9 | event log_array(int256[] val); 10 | event log_array(address[] val); 11 | event log_named_array(string key, uint256[] val); 12 | event log_named_array(string key, int256[] val); 13 | event log_named_array(string key, address[] val); 14 | 15 | function fail(string memory err) internal virtual { 16 | emit log_named_string("Error", err); 17 | fail(); 18 | } 19 | 20 | function assertFalse(bool data) internal virtual { 21 | assertTrue(!data); 22 | } 23 | 24 | function assertFalse(bool data, string memory err) internal virtual { 25 | assertTrue(!data, err); 26 | } 27 | 28 | function assertEq(bool a, bool b) internal virtual { 29 | if (a != b) { 30 | emit log("Error: a == b not satisfied [bool]"); 31 | emit log_named_string(" Expected", b ? "true" : "false"); 32 | emit log_named_string(" Actual", a ? "true" : "false"); 33 | fail(); 34 | } 35 | } 36 | 37 | function assertEq(bool a, bool b, string memory err) internal virtual { 38 | if (a != b) { 39 | emit log_named_string("Error", err); 40 | assertEq(a, b); 41 | } 42 | } 43 | 44 | function assertEq(bytes memory a, bytes memory b) internal virtual { 45 | assertEq0(a, b); 46 | } 47 | 48 | function assertEq(bytes memory a, bytes memory b, string memory err) internal virtual { 49 | assertEq0(a, b, err); 50 | } 51 | 52 | function assertEq(uint256[] memory a, uint256[] memory b) internal virtual { 53 | if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { 54 | emit log("Error: a == b not satisfied [uint[]]"); 55 | emit log_named_array(" Expected", b); 56 | emit log_named_array(" Actual", a); 57 | fail(); 58 | } 59 | } 60 | 61 | function assertEq(int256[] memory a, int256[] memory b) internal virtual { 62 | if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { 63 | emit log("Error: a == b not satisfied [int[]]"); 64 | emit log_named_array(" Expected", b); 65 | emit log_named_array(" Actual", a); 66 | fail(); 67 | } 68 | } 69 | 70 | function assertEq(address[] memory a, address[] memory b) internal virtual { 71 | if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { 72 | emit log("Error: a == b not satisfied [address[]]"); 73 | emit log_named_array(" Expected", b); 74 | emit log_named_array(" Actual", a); 75 | fail(); 76 | } 77 | } 78 | 79 | function assertEq(uint256[] memory a, uint256[] memory b, string memory err) internal virtual { 80 | if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { 81 | emit log_named_string("Error", err); 82 | assertEq(a, b); 83 | } 84 | } 85 | 86 | function assertEq(int256[] memory a, int256[] memory b, string memory err) internal virtual { 87 | if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { 88 | emit log_named_string("Error", err); 89 | assertEq(a, b); 90 | } 91 | } 92 | 93 | function assertEq(address[] memory a, address[] memory b, string memory err) internal virtual { 94 | if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { 95 | emit log_named_string("Error", err); 96 | assertEq(a, b); 97 | } 98 | } 99 | 100 | // Legacy helper 101 | function assertEqUint(uint256 a, uint256 b) internal virtual { 102 | assertEq(uint256(a), uint256(b)); 103 | } 104 | 105 | function assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta) internal virtual { 106 | uint256 delta = stdMath.delta(a, b); 107 | 108 | if (delta > maxDelta) { 109 | emit log("Error: a ~= b not satisfied [uint]"); 110 | emit log_named_uint(" Expected", b); 111 | emit log_named_uint(" Actual", a); 112 | emit log_named_uint(" Max Delta", maxDelta); 113 | emit log_named_uint(" Delta", delta); 114 | fail(); 115 | } 116 | } 117 | 118 | function assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta, string memory err) internal virtual { 119 | uint256 delta = stdMath.delta(a, b); 120 | 121 | if (delta > maxDelta) { 122 | emit log_named_string("Error", err); 123 | assertApproxEqAbs(a, b, maxDelta); 124 | } 125 | } 126 | 127 | function assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta) internal virtual { 128 | uint256 delta = stdMath.delta(a, b); 129 | 130 | if (delta > maxDelta) { 131 | emit log("Error: a ~= b not satisfied [int]"); 132 | emit log_named_int(" Expected", b); 133 | emit log_named_int(" Actual", a); 134 | emit log_named_uint(" Max Delta", maxDelta); 135 | emit log_named_uint(" Delta", delta); 136 | fail(); 137 | } 138 | } 139 | 140 | function assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta, string memory err) internal virtual { 141 | uint256 delta = stdMath.delta(a, b); 142 | 143 | if (delta > maxDelta) { 144 | emit log_named_string("Error", err); 145 | assertApproxEqAbs(a, b, maxDelta); 146 | } 147 | } 148 | 149 | function assertApproxEqRel( 150 | uint256 a, 151 | uint256 b, 152 | uint256 maxPercentDelta // An 18 decimal fixed point number, where 1e18 == 100% 153 | ) internal virtual { 154 | if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too. 155 | 156 | uint256 percentDelta = stdMath.percentDelta(a, b); 157 | 158 | if (percentDelta > maxPercentDelta) { 159 | emit log("Error: a ~= b not satisfied [uint]"); 160 | emit log_named_uint(" Expected", b); 161 | emit log_named_uint(" Actual", a); 162 | emit log_named_decimal_uint(" Max % Delta", maxPercentDelta, 18); 163 | emit log_named_decimal_uint(" % Delta", percentDelta, 18); 164 | fail(); 165 | } 166 | } 167 | 168 | function assertApproxEqRel( 169 | uint256 a, 170 | uint256 b, 171 | uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% 172 | string memory err 173 | ) internal virtual { 174 | if (b == 0) return assertEq(a, b, err); // If the expected is 0, actual must be too. 175 | 176 | uint256 percentDelta = stdMath.percentDelta(a, b); 177 | 178 | if (percentDelta > maxPercentDelta) { 179 | emit log_named_string("Error", err); 180 | assertApproxEqRel(a, b, maxPercentDelta); 181 | } 182 | } 183 | 184 | function assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta) internal virtual { 185 | if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too. 186 | 187 | uint256 percentDelta = stdMath.percentDelta(a, b); 188 | 189 | if (percentDelta > maxPercentDelta) { 190 | emit log("Error: a ~= b not satisfied [int]"); 191 | emit log_named_int(" Expected", b); 192 | emit log_named_int(" Actual", a); 193 | emit log_named_decimal_uint(" Max % Delta", maxPercentDelta, 18); 194 | emit log_named_decimal_uint(" % Delta", percentDelta, 18); 195 | fail(); 196 | } 197 | } 198 | 199 | function assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta, string memory err) internal virtual { 200 | if (b == 0) return assertEq(a, b, err); // If the expected is 0, actual must be too. 201 | 202 | uint256 percentDelta = stdMath.percentDelta(a, b); 203 | 204 | if (percentDelta > maxPercentDelta) { 205 | emit log_named_string("Error", err); 206 | assertApproxEqRel(a, b, maxPercentDelta); 207 | } 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/test/StdMath.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0 <0.9.0; 3 | 4 | import "../src/StdMath.sol"; 5 | import "../src/Test.sol"; 6 | 7 | contract StdMathTest is Test { 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 ? absA - absB : absB - absA; 93 | 94 | uint256 manualDelta; 95 | if ((a >= 0 && b >= 0) || (a < 0 && b < 0)) { 96 | manualDelta = absDelta; 97 | } 98 | // (a < 0 && b >= 0) || (a >= 0 && b < 0) 99 | else { 100 | manualDelta = absA + absB; 101 | } 102 | 103 | uint256 delta = stdMath.delta(a, b); 104 | 105 | assertEq(delta, manualDelta); 106 | } 107 | 108 | function testGetPercentDelta_Uint() external { 109 | assertEq(stdMath.percentDelta(uint256(0), uint256(1337)), 1e18); 110 | assertEq(stdMath.percentDelta(uint256(0), type(uint64).max), 1e18); 111 | assertEq(stdMath.percentDelta(uint256(0), type(uint128).max), 1e18); 112 | assertEq(stdMath.percentDelta(uint256(0), type(uint192).max), 1e18); 113 | 114 | assertEq(stdMath.percentDelta(1337, uint256(1337)), 0); 115 | assertEq(stdMath.percentDelta(type(uint192).max, type(uint192).max), 0); 116 | assertEq(stdMath.percentDelta(0, uint256(2500)), 1e18); 117 | assertEq(stdMath.percentDelta(2500, uint256(2500)), 0); 118 | assertEq(stdMath.percentDelta(5000, uint256(2500)), 1e18); 119 | assertEq(stdMath.percentDelta(7500, uint256(2500)), 2e18); 120 | 121 | vm.expectRevert(stdError.divisionError); 122 | stdMath.percentDelta(uint256(1), 0); 123 | } 124 | 125 | function testGetPercentDelta_Uint_Fuzz(uint192 a, uint192 b) external { 126 | vm.assume(b != 0); 127 | uint256 manualDelta; 128 | if (a > b) { 129 | manualDelta = a - b; 130 | } else { 131 | manualDelta = b - a; 132 | } 133 | 134 | uint256 manualPercentDelta = manualDelta * 1e18 / b; 135 | uint256 percentDelta = stdMath.percentDelta(a, b); 136 | 137 | assertEq(percentDelta, manualPercentDelta); 138 | } 139 | 140 | function testGetPercentDelta_Int() external { 141 | assertEq(stdMath.percentDelta(int256(0), int256(1337)), 1e18); 142 | assertEq(stdMath.percentDelta(int256(0), -1337), 1e18); 143 | assertEq(stdMath.percentDelta(int256(0), type(int64).min), 1e18); 144 | assertEq(stdMath.percentDelta(int256(0), type(int128).min), 1e18); 145 | assertEq(stdMath.percentDelta(int256(0), type(int192).min), 1e18); 146 | assertEq(stdMath.percentDelta(int256(0), type(int64).max), 1e18); 147 | assertEq(stdMath.percentDelta(int256(0), type(int128).max), 1e18); 148 | assertEq(stdMath.percentDelta(int256(0), type(int192).max), 1e18); 149 | 150 | assertEq(stdMath.percentDelta(1337, int256(1337)), 0); 151 | assertEq(stdMath.percentDelta(type(int192).max, type(int192).max), 0); 152 | assertEq(stdMath.percentDelta(type(int192).min, type(int192).min), 0); 153 | 154 | assertEq(stdMath.percentDelta(type(int192).min, type(int192).max), 2e18); // rounds the 1 wei diff down 155 | assertEq(stdMath.percentDelta(type(int192).max, type(int192).min), 2e18 - 1); // rounds the 1 wei diff down 156 | assertEq(stdMath.percentDelta(0, int256(2500)), 1e18); 157 | assertEq(stdMath.percentDelta(2500, int256(2500)), 0); 158 | assertEq(stdMath.percentDelta(5000, int256(2500)), 1e18); 159 | assertEq(stdMath.percentDelta(7500, int256(2500)), 2e18); 160 | 161 | vm.expectRevert(stdError.divisionError); 162 | stdMath.percentDelta(int256(1), 0); 163 | } 164 | 165 | function testGetPercentDelta_Int_Fuzz(int192 a, int192 b) external { 166 | vm.assume(b != 0); 167 | uint256 absA = getAbs(a); 168 | uint256 absB = getAbs(b); 169 | uint256 absDelta = absA > absB ? absA - absB : absB - absA; 170 | 171 | uint256 manualDelta; 172 | if ((a >= 0 && b >= 0) || (a < 0 && b < 0)) { 173 | manualDelta = absDelta; 174 | } 175 | // (a < 0 && b >= 0) || (a >= 0 && b < 0) 176 | else { 177 | manualDelta = absA + absB; 178 | } 179 | 180 | uint256 manualPercentDelta = manualDelta * 1e18 / absB; 181 | uint256 percentDelta = stdMath.percentDelta(a, b); 182 | 183 | assertEq(percentDelta, manualPercentDelta); 184 | } 185 | 186 | /*////////////////////////////////////////////////////////////////////////// 187 | HELPERS 188 | //////////////////////////////////////////////////////////////////////////*/ 189 | 190 | function getAbs(int256 a) private pure returns (uint256) { 191 | if (a < 0) { 192 | return a == type(int256).min ? uint256(type(int256).max) + 1 : uint256(-a); 193 | } 194 | 195 | return uint256(a); 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/README.md: -------------------------------------------------------------------------------- 1 | # Forge Standard Library • [![CI status](https://github.com/foundry-rs/forge-std/actions/workflows/ci.yml/badge.svg)](https://github.com/foundry-rs/forge-std/actions/workflows/ci.yml) 2 | 3 | Forge Standard Library is a collection of helpful contracts and libraries 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: MIT 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 | 248 | ## License 249 | 250 | Forge Standard Library is offered under either [MIT](LICENSE-MIT) or [Apache 2.0](LICENSE-APACHE) license. 251 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/src/interfaces/IERC721.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.6.2; 2 | 3 | import "./IERC165.sol"; 4 | 5 | /// @title ERC-721 Non-Fungible Token Standard 6 | /// @dev See https://eips.ethereum.org/EIPS/eip-721 7 | /// Note: the ERC-165 identifier for this interface is 0x80ac58cd. 8 | interface IERC721 is IERC165 { 9 | /// @dev This emits when ownership of any NFT changes by any mechanism. 10 | /// This event emits when NFTs are created (`from` == 0) and destroyed 11 | /// (`to` == 0). Exception: during contract creation, any number of NFTs 12 | /// may be created and assigned without emitting Transfer. At the time of 13 | /// any transfer, the approved address for that NFT (if any) is reset to none. 14 | event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); 15 | 16 | /// @dev This emits when the approved address for an NFT is changed or 17 | /// reaffirmed. The zero address indicates there is no approved address. 18 | /// When a Transfer event emits, this also indicates that the approved 19 | /// address for that NFT (if any) is reset to none. 20 | event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); 21 | 22 | /// @dev This emits when an operator is enabled or disabled for an owner. 23 | /// The operator can manage all NFTs of the owner. 24 | event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved); 25 | 26 | /// @notice Count all NFTs assigned to an owner 27 | /// @dev NFTs assigned to the zero address are considered invalid, and this 28 | /// function throws for queries about the zero address. 29 | /// @param _owner An address for whom to query the balance 30 | /// @return The number of NFTs owned by `_owner`, possibly zero 31 | function balanceOf(address _owner) external view returns (uint256); 32 | 33 | /// @notice Find the owner of an NFT 34 | /// @dev NFTs assigned to zero address are considered invalid, and queries 35 | /// about them do throw. 36 | /// @param _tokenId The identifier for an NFT 37 | /// @return The address of the owner of the NFT 38 | function ownerOf(uint256 _tokenId) external view returns (address); 39 | 40 | /// @notice Transfers the ownership of an NFT from one address to another address 41 | /// @dev Throws unless `msg.sender` is the current owner, an authorized 42 | /// operator, or the approved address for this NFT. Throws if `_from` is 43 | /// not the current owner. Throws if `_to` is the zero address. Throws if 44 | /// `_tokenId` is not a valid NFT. When transfer is complete, this function 45 | /// checks if `_to` is a smart contract (code size > 0). If so, it calls 46 | /// `onERC721Received` on `_to` and throws if the return value is not 47 | /// `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`. 48 | /// @param _from The current owner of the NFT 49 | /// @param _to The new owner 50 | /// @param _tokenId The NFT to transfer 51 | /// @param data Additional data with no specified format, sent in call to `_to` 52 | function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata data) external payable; 53 | 54 | /// @notice Transfers the ownership of an NFT from one address to another address 55 | /// @dev This works identically to the other function with an extra data parameter, 56 | /// except this function just sets data to "". 57 | /// @param _from The current owner of the NFT 58 | /// @param _to The new owner 59 | /// @param _tokenId The NFT to transfer 60 | function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable; 61 | 62 | /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE 63 | /// TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE 64 | /// THEY MAY BE PERMANENTLY LOST 65 | /// @dev Throws unless `msg.sender` is the current owner, an authorized 66 | /// operator, or the approved address for this NFT. Throws if `_from` is 67 | /// not the current owner. Throws if `_to` is the zero address. Throws if 68 | /// `_tokenId` is not a valid NFT. 69 | /// @param _from The current owner of the NFT 70 | /// @param _to The new owner 71 | /// @param _tokenId The NFT to transfer 72 | function transferFrom(address _from, address _to, uint256 _tokenId) external payable; 73 | 74 | /// @notice Change or reaffirm the approved address for an NFT 75 | /// @dev The zero address indicates there is no approved address. 76 | /// Throws unless `msg.sender` is the current NFT owner, or an authorized 77 | /// operator of the current owner. 78 | /// @param _approved The new approved NFT controller 79 | /// @param _tokenId The NFT to approve 80 | function approve(address _approved, uint256 _tokenId) external payable; 81 | 82 | /// @notice Enable or disable approval for a third party ("operator") to manage 83 | /// all of `msg.sender`'s assets 84 | /// @dev Emits the ApprovalForAll event. The contract MUST allow 85 | /// multiple operators per owner. 86 | /// @param _operator Address to add to the set of authorized operators 87 | /// @param _approved True if the operator is approved, false to revoke approval 88 | function setApprovalForAll(address _operator, bool _approved) external; 89 | 90 | /// @notice Get the approved address for a single NFT 91 | /// @dev Throws if `_tokenId` is not a valid NFT. 92 | /// @param _tokenId The NFT to find the approved address for 93 | /// @return The approved address for this NFT, or the zero address if there is none 94 | function getApproved(uint256 _tokenId) external view returns (address); 95 | 96 | /// @notice Query if an address is an authorized operator for another address 97 | /// @param _owner The address that owns the NFTs 98 | /// @param _operator The address that acts on behalf of the owner 99 | /// @return True if `_operator` is an approved operator for `_owner`, false otherwise 100 | function isApprovedForAll(address _owner, address _operator) external view returns (bool); 101 | } 102 | 103 | /// @dev Note: the ERC-165 identifier for this interface is 0x150b7a02. 104 | interface IERC721TokenReceiver { 105 | /// @notice Handle the receipt of an NFT 106 | /// @dev The ERC721 smart contract calls this function on the recipient 107 | /// after a `transfer`. This function MAY throw to revert and reject the 108 | /// transfer. Return of other than the magic value MUST result in the 109 | /// transaction being reverted. 110 | /// Note: the contract address is always the message sender. 111 | /// @param _operator The address which called `safeTransferFrom` function 112 | /// @param _from The address which previously owned the token 113 | /// @param _tokenId The NFT identifier which is being transferred 114 | /// @param _data Additional data with no specified format 115 | /// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` 116 | /// unless throwing 117 | function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes calldata _data) 118 | external 119 | returns (bytes4); 120 | } 121 | 122 | /// @title ERC-721 Non-Fungible Token Standard, optional metadata extension 123 | /// @dev See https://eips.ethereum.org/EIPS/eip-721 124 | /// Note: the ERC-165 identifier for this interface is 0x5b5e139f. 125 | interface IERC721Metadata is IERC721 { 126 | /// @notice A descriptive name for a collection of NFTs in this contract 127 | function name() external view returns (string memory _name); 128 | 129 | /// @notice An abbreviated name for NFTs in this contract 130 | function symbol() external view returns (string memory _symbol); 131 | 132 | /// @notice A distinct Uniform Resource Identifier (URI) for a given asset. 133 | /// @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC 134 | /// 3986. The URI may point to a JSON file that conforms to the "ERC721 135 | /// Metadata JSON Schema". 136 | function tokenURI(uint256 _tokenId) external view returns (string memory); 137 | } 138 | 139 | /// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension 140 | /// @dev See https://eips.ethereum.org/EIPS/eip-721 141 | /// Note: the ERC-165 identifier for this interface is 0x780e9d63. 142 | interface IERC721Enumerable is IERC721 { 143 | /// @notice Count NFTs tracked by this contract 144 | /// @return A count of valid NFTs tracked by this contract, where each one of 145 | /// them has an assigned and queryable owner not equal to the zero address 146 | function totalSupply() external view returns (uint256); 147 | 148 | /// @notice Enumerate valid NFTs 149 | /// @dev Throws if `_index` >= `totalSupply()`. 150 | /// @param _index A counter less than `totalSupply()` 151 | /// @return The token identifier for the `_index`th NFT, 152 | /// (sort order not specified) 153 | function tokenByIndex(uint256 _index) external view returns (uint256); 154 | 155 | /// @notice Enumerate NFTs assigned to an owner 156 | /// @dev Throws if `_index` >= `balanceOf(_owner)` or if 157 | /// `_owner` is the zero address, representing invalid NFTs. 158 | /// @param _owner An address where we are interested in NFTs owned by them 159 | /// @param _index A counter less than `balanceOf(_owner)` 160 | /// @return The token identifier for the `_index`th NFT assigned to `_owner`, 161 | /// (sort order not specified) 162 | function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256); 163 | } 164 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/test/fixtures/broadcast.log.json: -------------------------------------------------------------------------------- 1 | { 2 | "transactions": [ 3 | { 4 | "hash": "0xc6006863c267735a11476b7f15b15bc718e117e2da114a2be815dd651e1a509f", 5 | "type": "CALL", 6 | "contractName": "Test", 7 | "contractAddress": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", 8 | "function": "multiple_arguments(uint256,address,uint256[]):(uint256)", 9 | "arguments": ["1", "0000000000000000000000000000000000001337", "[3,4]"], 10 | "tx": { 11 | "type": "0x02", 12 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", 13 | "to": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", 14 | "gas": "0x73b9", 15 | "value": "0x0", 16 | "data": "0x23e99187000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000013370000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004", 17 | "nonce": "0x3", 18 | "accessList": [] 19 | } 20 | }, 21 | { 22 | "hash": "0xedf2b38d8d896519a947a1acf720f859bb35c0c5ecb8dd7511995b67b9853298", 23 | "type": "CALL", 24 | "contractName": "Test", 25 | "contractAddress": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", 26 | "function": "inc():(uint256)", 27 | "arguments": [], 28 | "tx": { 29 | "type": "0x02", 30 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", 31 | "to": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", 32 | "gas": "0xdcb2", 33 | "value": "0x0", 34 | "data": "0x371303c0", 35 | "nonce": "0x4", 36 | "accessList": [] 37 | } 38 | }, 39 | { 40 | "hash": "0xa57e8e3981a6c861442e46c9471bd19cb3e21f9a8a6c63a72e7b5c47c6675a7c", 41 | "type": "CALL", 42 | "contractName": "Test", 43 | "contractAddress": "0x7c6b4bbe207d642d98d5c537142d85209e585087", 44 | "function": "t(uint256):(uint256)", 45 | "arguments": ["1"], 46 | "tx": { 47 | "type": "0x02", 48 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", 49 | "to": "0x7c6b4bbe207d642d98d5c537142d85209e585087", 50 | "gas": "0x8599", 51 | "value": "0x0", 52 | "data": "0xafe29f710000000000000000000000000000000000000000000000000000000000000001", 53 | "nonce": "0x5", 54 | "accessList": [] 55 | } 56 | } 57 | ], 58 | "receipts": [ 59 | { 60 | "transactionHash": "0x481dc86e40bba90403c76f8e144aa9ff04c1da2164299d0298573835f0991181", 61 | "transactionIndex": "0x0", 62 | "blockHash": "0xef0730448490304e5403be0fa8f8ce64f118e9adcca60c07a2ae1ab921d748af", 63 | "blockNumber": "0x1", 64 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", 65 | "to": null, 66 | "cumulativeGasUsed": "0x13f3a", 67 | "gasUsed": "0x13f3a", 68 | "contractAddress": "0x5fbdb2315678afecb367f032d93f642f64180aa3", 69 | "logs": [], 70 | "status": "0x1", 71 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 72 | "effectiveGasPrice": "0xee6b2800" 73 | }, 74 | { 75 | "transactionHash": "0x6a187183545b8a9e7f1790e847139379bf5622baff2cb43acf3f5c79470af782", 76 | "transactionIndex": "0x0", 77 | "blockHash": "0xf3acb96a90071640c2a8c067ae4e16aad87e634ea8d8bbbb5b352fba86ba0148", 78 | "blockNumber": "0x2", 79 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", 80 | "to": null, 81 | "cumulativeGasUsed": "0x45d80", 82 | "gasUsed": "0x45d80", 83 | "contractAddress": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", 84 | "logs": [], 85 | "status": "0x1", 86 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 87 | "effectiveGasPrice": "0xee6b2800" 88 | }, 89 | { 90 | "transactionHash": "0x064ad173b4867bdef2fb60060bbdaf01735fbf10414541ea857772974e74ea9d", 91 | "transactionIndex": "0x0", 92 | "blockHash": "0x8373d02109d3ee06a0225f23da4c161c656ccc48fe0fcee931d325508ae73e58", 93 | "blockNumber": "0x3", 94 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", 95 | "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", 96 | "cumulativeGasUsed": "0x45feb", 97 | "gasUsed": "0x45feb", 98 | "contractAddress": null, 99 | "logs": [], 100 | "status": "0x1", 101 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 102 | "effectiveGasPrice": "0xee6b2800" 103 | }, 104 | { 105 | "transactionHash": "0xc6006863c267735a11476b7f15b15bc718e117e2da114a2be815dd651e1a509f", 106 | "transactionIndex": "0x0", 107 | "blockHash": "0x16712fae5c0e18f75045f84363fb6b4d9a9fe25e660c4ce286833a533c97f629", 108 | "blockNumber": "0x4", 109 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", 110 | "to": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", 111 | "cumulativeGasUsed": "0x5905", 112 | "gasUsed": "0x5905", 113 | "contractAddress": null, 114 | "logs": [], 115 | "status": "0x1", 116 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 117 | "effectiveGasPrice": "0xee6b2800" 118 | }, 119 | { 120 | "transactionHash": "0xedf2b38d8d896519a947a1acf720f859bb35c0c5ecb8dd7511995b67b9853298", 121 | "transactionIndex": "0x0", 122 | "blockHash": "0x156b88c3eb9a1244ba00a1834f3f70de735b39e3e59006dd03af4fe7d5480c11", 123 | "blockNumber": "0x5", 124 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", 125 | "to": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", 126 | "cumulativeGasUsed": "0xa9c4", 127 | "gasUsed": "0xa9c4", 128 | "contractAddress": null, 129 | "logs": [], 130 | "status": "0x1", 131 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 132 | "effectiveGasPrice": "0xee6b2800" 133 | }, 134 | { 135 | "transactionHash": "0xa57e8e3981a6c861442e46c9471bd19cb3e21f9a8a6c63a72e7b5c47c6675a7c", 136 | "transactionIndex": "0x0", 137 | "blockHash": "0xcf61faca67dbb2c28952b0b8a379e53b1505ae0821e84779679390cb8571cadb", 138 | "blockNumber": "0x6", 139 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", 140 | "to": "0x7c6b4bbe207d642d98d5c537142d85209e585087", 141 | "cumulativeGasUsed": "0x66c5", 142 | "gasUsed": "0x66c5", 143 | "contractAddress": null, 144 | "logs": [ 145 | { 146 | "address": "0x7c6b4bbe207d642d98d5c537142d85209e585087", 147 | "topics": [ 148 | "0x0b2e13ff20ac7b474198655583edf70dedd2c1dc980e329c4fbb2fc0748b796b" 149 | ], 150 | "data": "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000", 151 | "blockHash": "0xcf61faca67dbb2c28952b0b8a379e53b1505ae0821e84779679390cb8571cadb", 152 | "blockNumber": "0x6", 153 | "transactionHash": "0xa57e8e3981a6c861442e46c9471bd19cb3e21f9a8a6c63a72e7b5c47c6675a7c", 154 | "transactionIndex": "0x1", 155 | "logIndex": "0x0", 156 | "transactionLogIndex": "0x0", 157 | "removed": false 158 | } 159 | ], 160 | "status": "0x1", 161 | "logsBloom": "0x00000000000800000000000000000010000000000000000000000000000180000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100", 162 | "effectiveGasPrice": "0xee6b2800" 163 | }, 164 | { 165 | "transactionHash": "0x11fbb10230c168ca1e36a7e5c69a6dbcd04fd9e64ede39d10a83e36ee8065c16", 166 | "transactionIndex": "0x0", 167 | "blockHash": "0xf1e0ed2eda4e923626ec74621006ed50b3fc27580dc7b4cf68a07ca77420e29c", 168 | "blockNumber": "0x7", 169 | "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", 170 | "to": "0x0000000000000000000000000000000000001337", 171 | "cumulativeGasUsed": "0x5208", 172 | "gasUsed": "0x5208", 173 | "contractAddress": null, 174 | "logs": [], 175 | "status": "0x1", 176 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 177 | "effectiveGasPrice": "0xee6b2800" 178 | } 179 | ], 180 | "libraries": [ 181 | "src/Broadcast.t.sol:F:0x5fbdb2315678afecb367f032d93f642f64180aa3" 182 | ], 183 | "pending": [], 184 | "path": "broadcast/Broadcast.t.sol/31337/run-latest.json", 185 | "returns": {}, 186 | "timestamp": 1655140035 187 | } 188 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Copyright Contributors to Forge Standard Library 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 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/test/StdStorage.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.7.0 <0.9.0; 3 | 4 | import "../src/StdStorage.sol"; 5 | import "../src/Test.sol"; 6 | 7 | contract StdStorageTest is Test { 8 | using stdStorage for StdStorage; 9 | 10 | StorageTest internal test; 11 | 12 | function setUp() public { 13 | test = new StorageTest(); 14 | } 15 | 16 | function testStorageHidden() public { 17 | assertEq(uint256(keccak256("my.random.var")), stdstore.target(address(test)).sig("hidden()").find()); 18 | } 19 | 20 | function testStorageObvious() public { 21 | assertEq(uint256(0), stdstore.target(address(test)).sig("exists()").find()); 22 | } 23 | 24 | function testStorageCheckedWriteHidden() public { 25 | stdstore.target(address(test)).sig(test.hidden.selector).checked_write(100); 26 | assertEq(uint256(test.hidden()), 100); 27 | } 28 | 29 | function testStorageCheckedWriteObvious() public { 30 | stdstore.target(address(test)).sig(test.exists.selector).checked_write(100); 31 | assertEq(test.exists(), 100); 32 | } 33 | 34 | function testStorageMapStructA() public { 35 | uint256 slot = 36 | stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(0).find(); 37 | assertEq(uint256(keccak256(abi.encode(address(this), 4))), slot); 38 | } 39 | 40 | function testStorageMapStructB() public { 41 | uint256 slot = 42 | stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(1).find(); 43 | assertEq(uint256(keccak256(abi.encode(address(this), 4))) + 1, slot); 44 | } 45 | 46 | function testStorageDeepMap() public { 47 | uint256 slot = stdstore.target(address(test)).sig(test.deep_map.selector).with_key(address(this)).with_key( 48 | address(this) 49 | ).find(); 50 | assertEq(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint256(5)))))), slot); 51 | } 52 | 53 | function testStorageCheckedWriteDeepMap() public { 54 | stdstore.target(address(test)).sig(test.deep_map.selector).with_key(address(this)).with_key(address(this)) 55 | .checked_write(100); 56 | assertEq(100, test.deep_map(address(this), address(this))); 57 | } 58 | 59 | function testStorageDeepMapStructA() public { 60 | uint256 slot = stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)) 61 | .with_key(address(this)).depth(0).find(); 62 | assertEq( 63 | bytes32(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint256(6)))))) + 0), 64 | bytes32(slot) 65 | ); 66 | } 67 | 68 | function testStorageDeepMapStructB() public { 69 | uint256 slot = stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)) 70 | .with_key(address(this)).depth(1).find(); 71 | assertEq( 72 | bytes32(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint256(6)))))) + 1), 73 | bytes32(slot) 74 | ); 75 | } 76 | 77 | function testStorageCheckedWriteDeepMapStructA() public { 78 | stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)).with_key( 79 | address(this) 80 | ).depth(0).checked_write(100); 81 | (uint256 a, uint256 b) = test.deep_map_struct(address(this), address(this)); 82 | assertEq(100, a); 83 | assertEq(0, b); 84 | } 85 | 86 | function testStorageCheckedWriteDeepMapStructB() public { 87 | stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)).with_key( 88 | address(this) 89 | ).depth(1).checked_write(100); 90 | (uint256 a, uint256 b) = test.deep_map_struct(address(this), address(this)); 91 | assertEq(0, a); 92 | assertEq(100, b); 93 | } 94 | 95 | function testStorageCheckedWriteMapStructA() public { 96 | stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(0).checked_write(100); 97 | (uint256 a, uint256 b) = test.map_struct(address(this)); 98 | assertEq(a, 100); 99 | assertEq(b, 0); 100 | } 101 | 102 | function testStorageCheckedWriteMapStructB() public { 103 | stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(1).checked_write(100); 104 | (uint256 a, uint256 b) = test.map_struct(address(this)); 105 | assertEq(a, 0); 106 | assertEq(b, 100); 107 | } 108 | 109 | function testStorageStructA() public { 110 | uint256 slot = stdstore.target(address(test)).sig(test.basic.selector).depth(0).find(); 111 | assertEq(uint256(7), slot); 112 | } 113 | 114 | function testStorageStructB() public { 115 | uint256 slot = stdstore.target(address(test)).sig(test.basic.selector).depth(1).find(); 116 | assertEq(uint256(7) + 1, slot); 117 | } 118 | 119 | function testStorageCheckedWriteStructA() public { 120 | stdstore.target(address(test)).sig(test.basic.selector).depth(0).checked_write(100); 121 | (uint256 a, uint256 b) = test.basic(); 122 | assertEq(a, 100); 123 | assertEq(b, 1337); 124 | } 125 | 126 | function testStorageCheckedWriteStructB() public { 127 | stdstore.target(address(test)).sig(test.basic.selector).depth(1).checked_write(100); 128 | (uint256 a, uint256 b) = test.basic(); 129 | assertEq(a, 1337); 130 | assertEq(b, 100); 131 | } 132 | 133 | function testStorageMapAddrFound() public { 134 | uint256 slot = stdstore.target(address(test)).sig(test.map_addr.selector).with_key(address(this)).find(); 135 | assertEq(uint256(keccak256(abi.encode(address(this), uint256(1)))), slot); 136 | } 137 | 138 | function testStorageMapUintFound() public { 139 | uint256 slot = stdstore.target(address(test)).sig(test.map_uint.selector).with_key(100).find(); 140 | assertEq(uint256(keccak256(abi.encode(100, uint256(2)))), slot); 141 | } 142 | 143 | function testStorageCheckedWriteMapUint() public { 144 | stdstore.target(address(test)).sig(test.map_uint.selector).with_key(100).checked_write(100); 145 | assertEq(100, test.map_uint(100)); 146 | } 147 | 148 | function testStorageCheckedWriteMapAddr() public { 149 | stdstore.target(address(test)).sig(test.map_addr.selector).with_key(address(this)).checked_write(100); 150 | assertEq(100, test.map_addr(address(this))); 151 | } 152 | 153 | function testStorageCheckedWriteMapBool() public { 154 | stdstore.target(address(test)).sig(test.map_bool.selector).with_key(address(this)).checked_write(true); 155 | assertTrue(test.map_bool(address(this))); 156 | } 157 | 158 | function testFailStorageCheckedWriteMapPacked() public { 159 | // expect PackedSlot error but not external call so cant expectRevert 160 | stdstore.target(address(test)).sig(test.read_struct_lower.selector).with_key(address(uint160(1337))) 161 | .checked_write(100); 162 | } 163 | 164 | function testStorageCheckedWriteMapPackedSuccess() public { 165 | uint256 full = test.map_packed(address(1337)); 166 | // keep upper 128, set lower 128 to 1337 167 | full = (full & (uint256((1 << 128) - 1) << 128)) | 1337; 168 | stdstore.target(address(test)).sig(test.map_packed.selector).with_key(address(uint160(1337))).checked_write( 169 | full 170 | ); 171 | assertEq(1337, test.read_struct_lower(address(1337))); 172 | } 173 | 174 | function testFailStorageConst() public { 175 | // vm.expectRevert(abi.encodeWithSignature("NotStorage(bytes4)", bytes4(keccak256("const()")))); 176 | stdstore.target(address(test)).sig("const()").find(); 177 | } 178 | 179 | function testFailStorageNativePack() public { 180 | stdstore.target(address(test)).sig(test.tA.selector).find(); 181 | stdstore.target(address(test)).sig(test.tB.selector).find(); 182 | 183 | // these both would fail 184 | stdstore.target(address(test)).sig(test.tC.selector).find(); 185 | stdstore.target(address(test)).sig(test.tD.selector).find(); 186 | } 187 | 188 | function testStorageReadBytes32() public { 189 | bytes32 val = stdstore.target(address(test)).sig(test.tE.selector).read_bytes32(); 190 | assertEq(val, hex"1337"); 191 | } 192 | 193 | function testStorageReadBool_False() public { 194 | bool val = stdstore.target(address(test)).sig(test.tB.selector).read_bool(); 195 | assertEq(val, false); 196 | } 197 | 198 | function testStorageReadBool_True() public { 199 | bool val = stdstore.target(address(test)).sig(test.tH.selector).read_bool(); 200 | assertEq(val, true); 201 | } 202 | 203 | function testStorageReadBool_Revert() public { 204 | vm.expectRevert("stdStorage read_bool(StdStorage): Cannot decode. Make sure you are reading a bool."); 205 | this.readNonBoolValue(); 206 | } 207 | 208 | function readNonBoolValue() public { 209 | stdstore.target(address(test)).sig(test.tE.selector).read_bool(); 210 | } 211 | 212 | function testStorageReadAddress() public { 213 | address val = stdstore.target(address(test)).sig(test.tF.selector).read_address(); 214 | assertEq(val, address(1337)); 215 | } 216 | 217 | function testStorageReadUint() public { 218 | uint256 val = stdstore.target(address(test)).sig(test.exists.selector).read_uint(); 219 | assertEq(val, 1); 220 | } 221 | 222 | function testStorageReadInt() public { 223 | int256 val = stdstore.target(address(test)).sig(test.tG.selector).read_int(); 224 | assertEq(val, type(int256).min); 225 | } 226 | } 227 | 228 | contract StorageTest { 229 | uint256 public exists = 1; 230 | mapping(address => uint256) public map_addr; 231 | mapping(uint256 => uint256) public map_uint; 232 | mapping(address => uint256) public map_packed; 233 | mapping(address => UnpackedStruct) public map_struct; 234 | mapping(address => mapping(address => uint256)) public deep_map; 235 | mapping(address => mapping(address => UnpackedStruct)) public deep_map_struct; 236 | UnpackedStruct public basic; 237 | 238 | uint248 public tA; 239 | bool public tB; 240 | 241 | bool public tC = false; 242 | uint248 public tD = 1; 243 | 244 | struct UnpackedStruct { 245 | uint256 a; 246 | uint256 b; 247 | } 248 | 249 | mapping(address => bool) public map_bool; 250 | 251 | bytes32 public tE = hex"1337"; 252 | address public tF = address(1337); 253 | int256 public tG = type(int256).min; 254 | bool public tH = true; 255 | 256 | constructor() { 257 | basic = UnpackedStruct({a: 1337, b: 1337}); 258 | 259 | uint256 two = (1 << 128) | 1; 260 | map_packed[msg.sender] = two; 261 | map_packed[address(uint160(1337))] = 1 << 128; 262 | } 263 | 264 | function read_struct_upper(address who) public view returns (uint256) { 265 | return map_packed[who] >> 128; 266 | } 267 | 268 | function read_struct_lower(address who) public view returns (uint256) { 269 | return map_packed[who] & ((1 << 128) - 1); 270 | } 271 | 272 | function hidden() public view returns (bytes32 t) { 273 | bytes32 slot = keccak256("my.random.var"); 274 | /// @solidity memory-safe-assembly 275 | assembly { 276 | t := sload(slot) 277 | } 278 | } 279 | 280 | function const() public pure returns (bytes32 t) { 281 | t = bytes32(hex"1337"); 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/test/StdCheats.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.7.0 <0.9.0; 3 | 4 | import "../src/StdCheats.sol"; 5 | import "../src/Test.sol"; 6 | import "../src/StdJson.sol"; 7 | 8 | contract StdCheatsTest is Test { 9 | Bar test; 10 | 11 | using stdJson for string; 12 | 13 | function setUp() public { 14 | test = new Bar(); 15 | } 16 | 17 | function testSkip() public { 18 | vm.warp(100); 19 | skip(25); 20 | assertEq(block.timestamp, 125); 21 | } 22 | 23 | function testRewind() public { 24 | vm.warp(100); 25 | rewind(25); 26 | assertEq(block.timestamp, 75); 27 | } 28 | 29 | function testHoax() public { 30 | hoax(address(1337)); 31 | test.bar{value: 100}(address(1337)); 32 | } 33 | 34 | function testHoaxOrigin() public { 35 | hoax(address(1337), address(1337)); 36 | test.origin{value: 100}(address(1337)); 37 | } 38 | 39 | function testHoaxDifferentAddresses() public { 40 | hoax(address(1337), address(7331)); 41 | test.origin{value: 100}(address(1337), address(7331)); 42 | } 43 | 44 | function testStartHoax() public { 45 | startHoax(address(1337)); 46 | test.bar{value: 100}(address(1337)); 47 | test.bar{value: 100}(address(1337)); 48 | vm.stopPrank(); 49 | test.bar(address(this)); 50 | } 51 | 52 | function testStartHoaxOrigin() public { 53 | startHoax(address(1337), address(1337)); 54 | test.origin{value: 100}(address(1337)); 55 | test.origin{value: 100}(address(1337)); 56 | vm.stopPrank(); 57 | test.bar(address(this)); 58 | } 59 | 60 | function testChangePrank() public { 61 | vm.startPrank(address(1337)); 62 | test.bar(address(1337)); 63 | changePrank(address(0xdead)); 64 | test.bar(address(0xdead)); 65 | changePrank(address(1337)); 66 | test.bar(address(1337)); 67 | vm.stopPrank(); 68 | } 69 | 70 | function testMakeAddrEquivalence() public { 71 | (address addr,) = makeAddrAndKey("1337"); 72 | assertEq(makeAddr("1337"), addr); 73 | } 74 | 75 | function testMakeAddrSigning() public { 76 | (address addr, uint256 key) = makeAddrAndKey("1337"); 77 | bytes32 hash = keccak256("some_message"); 78 | 79 | (uint8 v, bytes32 r, bytes32 s) = vm.sign(key, hash); 80 | assertEq(ecrecover(hash, v, r, s), addr); 81 | } 82 | 83 | function testDeal() public { 84 | deal(address(this), 1 ether); 85 | assertEq(address(this).balance, 1 ether); 86 | } 87 | 88 | function testDealToken() public { 89 | Bar barToken = new Bar(); 90 | address bar = address(barToken); 91 | deal(bar, address(this), 10000e18); 92 | assertEq(barToken.balanceOf(address(this)), 10000e18); 93 | } 94 | 95 | function testDealTokenAdjustTS() public { 96 | Bar barToken = new Bar(); 97 | address bar = address(barToken); 98 | deal(bar, address(this), 10000e18, true); 99 | assertEq(barToken.balanceOf(address(this)), 10000e18); 100 | assertEq(barToken.totalSupply(), 20000e18); 101 | deal(bar, address(this), 0, true); 102 | assertEq(barToken.balanceOf(address(this)), 0); 103 | assertEq(barToken.totalSupply(), 10000e18); 104 | } 105 | 106 | function testDeployCode() public { 107 | address deployed = deployCode("StdCheats.t.sol:Bar", bytes("")); 108 | assertEq(string(getCode(deployed)), string(getCode(address(test)))); 109 | } 110 | 111 | function testDeployCodeNoArgs() public { 112 | address deployed = deployCode("StdCheats.t.sol:Bar"); 113 | assertEq(string(getCode(deployed)), string(getCode(address(test)))); 114 | } 115 | 116 | function testDeployCodeVal() public { 117 | address deployed = deployCode("StdCheats.t.sol:Bar", bytes(""), 1 ether); 118 | assertEq(string(getCode(deployed)), string(getCode(address(test)))); 119 | assertEq(deployed.balance, 1 ether); 120 | } 121 | 122 | function testDeployCodeValNoArgs() public { 123 | address deployed = deployCode("StdCheats.t.sol:Bar", 1 ether); 124 | assertEq(string(getCode(deployed)), string(getCode(address(test)))); 125 | assertEq(deployed.balance, 1 ether); 126 | } 127 | 128 | // We need this so we can call "this.deployCode" rather than "deployCode" directly 129 | function deployCodeHelper(string memory what) external { 130 | deployCode(what); 131 | } 132 | 133 | function testDeployCodeFail() public { 134 | vm.expectRevert(bytes("StdCheats deployCode(string): Deployment failed.")); 135 | this.deployCodeHelper("StdCheats.t.sol:RevertingContract"); 136 | } 137 | 138 | function getCode(address who) internal view returns (bytes memory o_code) { 139 | /// @solidity memory-safe-assembly 140 | assembly { 141 | // retrieve the size of the code, this needs assembly 142 | let size := extcodesize(who) 143 | // allocate output byte array - this could also be done without assembly 144 | // by using o_code = new bytes(size) 145 | o_code := mload(0x40) 146 | // new "memory end" including padding 147 | mstore(0x40, add(o_code, and(add(add(size, 0x20), 0x1f), not(0x1f)))) 148 | // store length in memory 149 | mstore(o_code, size) 150 | // actually retrieve the code, this needs assembly 151 | extcodecopy(who, add(o_code, 0x20), 0, size) 152 | } 153 | } 154 | 155 | function testDeriveRememberKey() public { 156 | string memory mnemonic = "test test test test test test test test test test test junk"; 157 | 158 | (address deployer, uint256 privateKey) = deriveRememberKey(mnemonic, 0); 159 | assertEq(deployer, 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266); 160 | assertEq(privateKey, 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80); 161 | } 162 | 163 | function testBytesToUint() public { 164 | assertEq(3, bytesToUint_test(hex"03")); 165 | assertEq(2, bytesToUint_test(hex"02")); 166 | assertEq(255, bytesToUint_test(hex"ff")); 167 | assertEq(29625, bytesToUint_test(hex"73b9")); 168 | } 169 | 170 | function testParseJsonTxDetail() public { 171 | string memory root = vm.projectRoot(); 172 | string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); 173 | string memory json = vm.readFile(path); 174 | bytes memory transactionDetails = json.parseRaw(".transactions[0].tx"); 175 | RawTx1559Detail memory rawTxDetail = abi.decode(transactionDetails, (RawTx1559Detail)); 176 | Tx1559Detail memory txDetail = rawToConvertedEIP1559Detail(rawTxDetail); 177 | assertEq(txDetail.from, 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266); 178 | assertEq(txDetail.to, 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512); 179 | assertEq( 180 | txDetail.data, 181 | hex"23e99187000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000013370000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004" 182 | ); 183 | assertEq(txDetail.nonce, 3); 184 | assertEq(txDetail.txType, 2); 185 | assertEq(txDetail.gas, 29625); 186 | assertEq(txDetail.value, 0); 187 | } 188 | 189 | function testReadEIP1559Transaction() public { 190 | string memory root = vm.projectRoot(); 191 | string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); 192 | uint256 index = 0; 193 | Tx1559 memory transaction = readTx1559(path, index); 194 | transaction; 195 | } 196 | 197 | function testReadEIP1559Transactions() public { 198 | string memory root = vm.projectRoot(); 199 | string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); 200 | Tx1559[] memory transactions = readTx1559s(path); 201 | transactions; 202 | } 203 | 204 | function testReadReceipt() public { 205 | string memory root = vm.projectRoot(); 206 | string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); 207 | uint256 index = 5; 208 | Receipt memory receipt = readReceipt(path, index); 209 | assertEq( 210 | receipt.logsBloom, 211 | hex"00000000000800000000000000000010000000000000000000000000000180000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100" 212 | ); 213 | } 214 | 215 | function testReadReceipts() public { 216 | string memory root = vm.projectRoot(); 217 | string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); 218 | Receipt[] memory receipts = readReceipts(path); 219 | receipts; 220 | } 221 | 222 | function bytesToUint_test(bytes memory b) private pure returns (uint256) { 223 | uint256 number; 224 | for (uint256 i = 0; i < b.length; i++) { 225 | number = number + uint256(uint8(b[i])) * (2 ** (8 * (b.length - (i + 1)))); 226 | } 227 | return number; 228 | } 229 | 230 | function testChainRpcInitialization() public { 231 | // RPCs specified in `foundry.toml` should be updated. 232 | assertEq(stdChains.Mainnet.rpcUrl, "https://api.mycryptoapi.com/eth/"); 233 | assertEq(stdChains.OptimismGoerli.rpcUrl, "https://goerli.optimism.io/"); 234 | assertEq(stdChains.ArbitrumOneGoerli.rpcUrl, "https://goerli-rollup.arbitrum.io/rpc/"); 235 | 236 | // Other RPCs should remain unchanged. 237 | assertEq(stdChains.Anvil.rpcUrl, "http://127.0.0.1:8545"); 238 | assertEq(stdChains.Hardhat.rpcUrl, "http://127.0.0.1:8545"); 239 | assertEq(stdChains.Sepolia.rpcUrl, "https://rpc.sepolia.dev"); 240 | } 241 | 242 | // Ensure we can connect to the default RPC URL for each chain. 243 | function testRpcs() public { 244 | (string[2][] memory rpcs) = vm.rpcUrls(); 245 | for (uint256 i = 0; i < rpcs.length; i++) { 246 | ( /* string memory name */ , string memory rpcUrl) = (rpcs[i][0], rpcs[i][1]); 247 | vm.createSelectFork(rpcUrl); 248 | } 249 | } 250 | } 251 | 252 | contract Bar { 253 | constructor() payable { 254 | /// `DEAL` STDCHEAT 255 | totalSupply = 10000e18; 256 | balanceOf[address(this)] = totalSupply; 257 | } 258 | 259 | /// `HOAX` STDCHEATS 260 | function bar(address expectedSender) public payable { 261 | require(msg.sender == expectedSender, "!prank"); 262 | } 263 | 264 | function origin(address expectedSender) public payable { 265 | require(msg.sender == expectedSender, "!prank"); 266 | require(tx.origin == expectedSender, "!prank"); 267 | } 268 | 269 | function origin(address expectedSender, address expectedOrigin) public payable { 270 | require(msg.sender == expectedSender, "!prank"); 271 | require(tx.origin == expectedOrigin, "!prank"); 272 | } 273 | 274 | /// `DEAL` STDCHEAT 275 | mapping(address => uint256) public balanceOf; 276 | uint256 public totalSupply; 277 | } 278 | 279 | contract RevertingContract { 280 | constructor() { 281 | revert(); 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/src/interfaces/IERC4626.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.6.2; 2 | 3 | import "./IERC20.sol"; 4 | 5 | /// @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in 6 | /// https://eips.ethereum.org/EIPS/eip-4626 7 | interface IERC4626 is IERC20 { 8 | event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares); 9 | 10 | event Withdraw( 11 | address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares 12 | ); 13 | 14 | /// @notice Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing. 15 | /// @dev 16 | /// - MUST be an ERC-20 token contract. 17 | /// - MUST NOT revert. 18 | function asset() external view returns (address assetTokenAddress); 19 | 20 | /// @notice Returns the total amount of the underlying asset that is “managed” by Vault. 21 | /// @dev 22 | /// - SHOULD include any compounding that occurs from yield. 23 | /// - MUST be inclusive of any fees that are charged against assets in the Vault. 24 | /// - MUST NOT revert. 25 | function totalAssets() external view returns (uint256 totalManagedAssets); 26 | 27 | /// @notice Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal 28 | /// scenario where all the conditions are met. 29 | /// @dev 30 | /// - MUST NOT be inclusive of any fees that are charged against assets in the Vault. 31 | /// - MUST NOT show any variations depending on the caller. 32 | /// - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. 33 | /// - MUST NOT revert. 34 | /// 35 | /// NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the 36 | /// “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and 37 | /// from. 38 | function convertToShares(uint256 assets) external view returns (uint256 shares); 39 | 40 | /// @notice Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal 41 | /// scenario where all the conditions are met. 42 | /// @dev 43 | /// - MUST NOT be inclusive of any fees that are charged against assets in the Vault. 44 | /// - MUST NOT show any variations depending on the caller. 45 | /// - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. 46 | /// - MUST NOT revert. 47 | /// 48 | /// NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the 49 | /// “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and 50 | /// from. 51 | function convertToAssets(uint256 shares) external view returns (uint256 assets); 52 | 53 | /// @notice Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver, 54 | /// through a deposit call. 55 | /// @dev 56 | /// - MUST return a limited value if receiver is subject to some deposit limit. 57 | /// - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited. 58 | /// - MUST NOT revert. 59 | function maxDeposit(address receiver) external view returns (uint256 maxAssets); 60 | 61 | /// @notice Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given 62 | /// current on-chain conditions. 63 | /// @dev 64 | /// - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit 65 | /// call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called 66 | /// in the same transaction. 67 | /// - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the 68 | /// deposit would be accepted, regardless if the user has enough tokens approved, etc. 69 | /// - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. 70 | /// - MUST NOT revert. 71 | /// 72 | /// NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in 73 | /// share price or some other type of condition, meaning the depositor will lose assets by depositing. 74 | function previewDeposit(uint256 assets) external view returns (uint256 shares); 75 | 76 | /// @notice Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens. 77 | /// @dev 78 | /// - MUST emit the Deposit event. 79 | /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the 80 | /// deposit execution, and are accounted for during deposit. 81 | /// - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not 82 | /// approving enough underlying tokens to the Vault contract, etc). 83 | /// 84 | /// NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. 85 | function deposit(uint256 assets, address receiver) external returns (uint256 shares); 86 | 87 | /// @notice Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call. 88 | /// @dev 89 | /// - MUST return a limited value if receiver is subject to some mint limit. 90 | /// - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted. 91 | /// - MUST NOT revert. 92 | function maxMint(address receiver) external view returns (uint256 maxShares); 93 | 94 | /// @notice Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given 95 | /// current on-chain conditions. 96 | /// @dev 97 | /// - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call 98 | /// in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the 99 | /// same transaction. 100 | /// - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint 101 | /// would be accepted, regardless if the user has enough tokens approved, etc. 102 | /// - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. 103 | /// - MUST NOT revert. 104 | /// 105 | /// NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in 106 | /// share price or some other type of condition, meaning the depositor will lose assets by minting. 107 | function previewMint(uint256 shares) external view returns (uint256 assets); 108 | 109 | /// @notice Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens. 110 | /// @dev 111 | /// - MUST emit the Deposit event. 112 | /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint 113 | /// execution, and are accounted for during mint. 114 | /// - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not 115 | /// approving enough underlying tokens to the Vault contract, etc). 116 | /// 117 | /// NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. 118 | function mint(uint256 shares, address receiver) external returns (uint256 assets); 119 | 120 | /// @notice Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the 121 | /// Vault, through a withdraw call. 122 | /// @dev 123 | /// - MUST return a limited value if owner is subject to some withdrawal limit or timelock. 124 | /// - MUST NOT revert. 125 | function maxWithdraw(address owner) external view returns (uint256 maxAssets); 126 | 127 | /// @notice Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block, 128 | /// given current on-chain conditions. 129 | /// @dev 130 | /// - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw 131 | /// call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if 132 | /// called 133 | /// in the same transaction. 134 | /// - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though 135 | /// the withdrawal would be accepted, regardless if the user has enough shares, etc. 136 | /// - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. 137 | /// - MUST NOT revert. 138 | /// 139 | /// NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in 140 | /// share price or some other type of condition, meaning the depositor will lose assets by depositing. 141 | function previewWithdraw(uint256 assets) external view returns (uint256 shares); 142 | 143 | /// @notice Burns shares from owner and sends exactly assets of underlying tokens to receiver. 144 | /// @dev 145 | /// - MUST emit the Withdraw event. 146 | /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the 147 | /// withdraw execution, and are accounted for during withdraw. 148 | /// - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner 149 | /// not having enough shares, etc). 150 | /// 151 | /// Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed. 152 | /// Those methods should be performed separately. 153 | function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares); 154 | 155 | /// @notice Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault, 156 | /// through a redeem call. 157 | /// @dev 158 | /// - MUST return a limited value if owner is subject to some withdrawal limit or timelock. 159 | /// - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock. 160 | /// - MUST NOT revert. 161 | function maxRedeem(address owner) external view returns (uint256 maxShares); 162 | 163 | /// @notice Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block, 164 | /// given current on-chain conditions. 165 | /// @dev 166 | /// - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call 167 | /// in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the 168 | /// same transaction. 169 | /// - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the 170 | /// redemption would be accepted, regardless if the user has enough shares, etc. 171 | /// - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. 172 | /// - MUST NOT revert. 173 | /// 174 | /// NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in 175 | /// share price or some other type of condition, meaning the depositor will lose assets by redeeming. 176 | function previewRedeem(uint256 shares) external view returns (uint256 assets); 177 | 178 | /// @notice Burns exactly shares from owner and sends assets of underlying tokens to receiver. 179 | /// @dev 180 | /// - MUST emit the Withdraw event. 181 | /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the 182 | /// redeem execution, and are accounted for during redeem. 183 | /// - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner 184 | /// not having enough shares, etc). 185 | /// 186 | /// NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed. 187 | /// Those methods should be performed separately. 188 | function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets); 189 | } 190 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/src/StdStorage.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | import "./Vm.sol"; 5 | 6 | struct StdStorage { 7 | mapping(address => mapping(bytes4 => mapping(bytes32 => uint256))) slots; 8 | mapping(address => mapping(bytes4 => mapping(bytes32 => bool))) finds; 9 | bytes32[] _keys; 10 | bytes4 _sig; 11 | uint256 _depth; 12 | address _target; 13 | bytes32 _set; 14 | } 15 | 16 | library stdStorageSafe { 17 | event SlotFound(address who, bytes4 fsig, bytes32 keysHash, uint256 slot); 18 | event WARNING_UninitedSlot(address who, uint256 slot); 19 | 20 | Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); 21 | 22 | function sigs(string memory sigStr) internal pure returns (bytes4) { 23 | return bytes4(keccak256(bytes(sigStr))); 24 | } 25 | 26 | /// @notice find an arbitrary storage slot given a function sig, input data, address of the contract and a value to check against 27 | // slot complexity: 28 | // if flat, will be bytes32(uint256(uint)); 29 | // if map, will be keccak256(abi.encode(key, uint(slot))); 30 | // if deep map, will be keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot))))); 31 | // if map struct, will be bytes32(uint256(keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot)))))) + structFieldDepth); 32 | function find(StdStorage storage self) internal returns (uint256) { 33 | address who = self._target; 34 | bytes4 fsig = self._sig; 35 | uint256 field_depth = self._depth; 36 | bytes32[] memory ins = self._keys; 37 | 38 | // calldata to test against 39 | if (self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]) { 40 | return self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]; 41 | } 42 | bytes memory cald = abi.encodePacked(fsig, flatten(ins)); 43 | vm.record(); 44 | bytes32 fdat; 45 | { 46 | (, bytes memory rdat) = who.staticcall(cald); 47 | fdat = bytesToBytes32(rdat, 32 * field_depth); 48 | } 49 | 50 | (bytes32[] memory reads,) = vm.accesses(address(who)); 51 | if (reads.length == 1) { 52 | bytes32 curr = vm.load(who, reads[0]); 53 | if (curr == bytes32(0)) { 54 | emit WARNING_UninitedSlot(who, uint256(reads[0])); 55 | } 56 | if (fdat != curr) { 57 | require( 58 | false, 59 | "stdStorage find(StdStorage): Packed slot. This would cause dangerous overwriting and currently isn't supported." 60 | ); 61 | } 62 | emit SlotFound(who, fsig, keccak256(abi.encodePacked(ins, field_depth)), uint256(reads[0])); 63 | self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = uint256(reads[0]); 64 | self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = true; 65 | } else if (reads.length > 1) { 66 | for (uint256 i = 0; i < reads.length; i++) { 67 | bytes32 prev = vm.load(who, reads[i]); 68 | if (prev == bytes32(0)) { 69 | emit WARNING_UninitedSlot(who, uint256(reads[i])); 70 | } 71 | // store 72 | vm.store(who, reads[i], bytes32(hex"1337")); 73 | bool success; 74 | bytes memory rdat; 75 | { 76 | (success, rdat) = who.staticcall(cald); 77 | fdat = bytesToBytes32(rdat, 32 * field_depth); 78 | } 79 | 80 | if (success && fdat == bytes32(hex"1337")) { 81 | // we found which of the slots is the actual one 82 | emit SlotFound(who, fsig, keccak256(abi.encodePacked(ins, field_depth)), uint256(reads[i])); 83 | self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = uint256(reads[i]); 84 | self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = true; 85 | vm.store(who, reads[i], prev); 86 | break; 87 | } 88 | vm.store(who, reads[i], prev); 89 | } 90 | } else { 91 | require(false, "stdStorage find(StdStorage): No storage use detected for target."); 92 | } 93 | 94 | require( 95 | self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))], 96 | "stdStorage find(StdStorage): Slot(s) not found." 97 | ); 98 | 99 | delete self._target; 100 | delete self._sig; 101 | delete self._keys; 102 | delete self._depth; 103 | 104 | return self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]; 105 | } 106 | 107 | function target(StdStorage storage self, address _target) internal returns (StdStorage storage) { 108 | self._target = _target; 109 | return self; 110 | } 111 | 112 | function sig(StdStorage storage self, bytes4 _sig) internal returns (StdStorage storage) { 113 | self._sig = _sig; 114 | return self; 115 | } 116 | 117 | function sig(StdStorage storage self, string memory _sig) internal returns (StdStorage storage) { 118 | self._sig = sigs(_sig); 119 | return self; 120 | } 121 | 122 | function with_key(StdStorage storage self, address who) internal returns (StdStorage storage) { 123 | self._keys.push(bytes32(uint256(uint160(who)))); 124 | return self; 125 | } 126 | 127 | function with_key(StdStorage storage self, uint256 amt) internal returns (StdStorage storage) { 128 | self._keys.push(bytes32(amt)); 129 | return self; 130 | } 131 | 132 | function with_key(StdStorage storage self, bytes32 key) internal returns (StdStorage storage) { 133 | self._keys.push(key); 134 | return self; 135 | } 136 | 137 | function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) { 138 | self._depth = _depth; 139 | return self; 140 | } 141 | 142 | function read(StdStorage storage self) private returns (bytes memory) { 143 | address t = self._target; 144 | uint256 s = find(self); 145 | return abi.encode(vm.load(t, bytes32(s))); 146 | } 147 | 148 | function read_bytes32(StdStorage storage self) internal returns (bytes32) { 149 | return abi.decode(read(self), (bytes32)); 150 | } 151 | 152 | function read_bool(StdStorage storage self) internal returns (bool) { 153 | int256 v = read_int(self); 154 | if (v == 0) return false; 155 | if (v == 1) return true; 156 | revert("stdStorage read_bool(StdStorage): Cannot decode. Make sure you are reading a bool."); 157 | } 158 | 159 | function read_address(StdStorage storage self) internal returns (address) { 160 | return abi.decode(read(self), (address)); 161 | } 162 | 163 | function read_uint(StdStorage storage self) internal returns (uint256) { 164 | return abi.decode(read(self), (uint256)); 165 | } 166 | 167 | function read_int(StdStorage storage self) internal returns (int256) { 168 | return abi.decode(read(self), (int256)); 169 | } 170 | 171 | function bytesToBytes32(bytes memory b, uint256 offset) private pure returns (bytes32) { 172 | bytes32 out; 173 | 174 | uint256 max = b.length > 32 ? 32 : b.length; 175 | for (uint256 i = 0; i < max; i++) { 176 | out |= bytes32(b[offset + i] & 0xFF) >> (i * 8); 177 | } 178 | return out; 179 | } 180 | 181 | function flatten(bytes32[] memory b) private pure returns (bytes memory) { 182 | bytes memory result = new bytes(b.length * 32); 183 | for (uint256 i = 0; i < b.length; i++) { 184 | bytes32 k = b[i]; 185 | /// @solidity memory-safe-assembly 186 | assembly { 187 | mstore(add(result, add(32, mul(32, i))), k) 188 | } 189 | } 190 | 191 | return result; 192 | } 193 | } 194 | 195 | library stdStorage { 196 | Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); 197 | 198 | function sigs(string memory sigStr) internal pure returns (bytes4) { 199 | return stdStorageSafe.sigs(sigStr); 200 | } 201 | 202 | function find(StdStorage storage self) internal returns (uint256) { 203 | return stdStorageSafe.find(self); 204 | } 205 | 206 | function target(StdStorage storage self, address _target) internal returns (StdStorage storage) { 207 | return stdStorageSafe.target(self, _target); 208 | } 209 | 210 | function sig(StdStorage storage self, bytes4 _sig) internal returns (StdStorage storage) { 211 | return stdStorageSafe.sig(self, _sig); 212 | } 213 | 214 | function sig(StdStorage storage self, string memory _sig) internal returns (StdStorage storage) { 215 | return stdStorageSafe.sig(self, _sig); 216 | } 217 | 218 | function with_key(StdStorage storage self, address who) internal returns (StdStorage storage) { 219 | return stdStorageSafe.with_key(self, who); 220 | } 221 | 222 | function with_key(StdStorage storage self, uint256 amt) internal returns (StdStorage storage) { 223 | return stdStorageSafe.with_key(self, amt); 224 | } 225 | 226 | function with_key(StdStorage storage self, bytes32 key) internal returns (StdStorage storage) { 227 | return stdStorageSafe.with_key(self, key); 228 | } 229 | 230 | function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) { 231 | return stdStorageSafe.depth(self, _depth); 232 | } 233 | 234 | function checked_write(StdStorage storage self, address who) internal { 235 | checked_write(self, bytes32(uint256(uint160(who)))); 236 | } 237 | 238 | function checked_write(StdStorage storage self, uint256 amt) internal { 239 | checked_write(self, bytes32(amt)); 240 | } 241 | 242 | function checked_write(StdStorage storage self, bool write) internal { 243 | bytes32 t; 244 | /// @solidity memory-safe-assembly 245 | assembly { 246 | t := write 247 | } 248 | checked_write(self, t); 249 | } 250 | 251 | function checked_write(StdStorage storage self, bytes32 set) internal { 252 | address who = self._target; 253 | bytes4 fsig = self._sig; 254 | uint256 field_depth = self._depth; 255 | bytes32[] memory ins = self._keys; 256 | 257 | bytes memory cald = abi.encodePacked(fsig, flatten(ins)); 258 | if (!self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]) { 259 | find(self); 260 | } 261 | bytes32 slot = bytes32(self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]); 262 | 263 | bytes32 fdat; 264 | { 265 | (, bytes memory rdat) = who.staticcall(cald); 266 | fdat = bytesToBytes32(rdat, 32 * field_depth); 267 | } 268 | bytes32 curr = vm.load(who, slot); 269 | 270 | if (fdat != curr) { 271 | require( 272 | false, 273 | "stdStorage find(StdStorage): Packed slot. This would cause dangerous overwriting and currently isn't supported." 274 | ); 275 | } 276 | vm.store(who, slot, set); 277 | delete self._target; 278 | delete self._sig; 279 | delete self._keys; 280 | delete self._depth; 281 | } 282 | 283 | function read_bytes32(StdStorage storage self) internal returns (bytes32) { 284 | return stdStorageSafe.read_bytes32(self); 285 | } 286 | 287 | function read_bool(StdStorage storage self) internal returns (bool) { 288 | return stdStorageSafe.read_bool(self); 289 | } 290 | 291 | function read_address(StdStorage storage self) internal returns (address) { 292 | return stdStorageSafe.read_address(self); 293 | } 294 | 295 | function read_uint(StdStorage storage self) internal returns (uint256) { 296 | return stdStorageSafe.read_uint(self); 297 | } 298 | 299 | function read_int(StdStorage storage self) internal returns (int256) { 300 | return stdStorageSafe.read_int(self); 301 | } 302 | 303 | // Private function so needs to be copied over 304 | function bytesToBytes32(bytes memory b, uint256 offset) private pure returns (bytes32) { 305 | bytes32 out; 306 | 307 | uint256 max = b.length > 32 ? 32 : b.length; 308 | for (uint256 i = 0; i < max; i++) { 309 | out |= bytes32(b[offset + i] & 0xFF) >> (i * 8); 310 | } 311 | return out; 312 | } 313 | 314 | // Private function so needs to be copied over 315 | function flatten(bytes32[] memory b) private pure returns (bytes memory) { 316 | bytes memory result = new bytes(b.length * 32); 317 | for (uint256 i = 0; i < b.length; i++) { 318 | bytes32 k = b[i]; 319 | /// @solidity memory-safe-assembly 320 | assembly { 321 | mstore(add(result, add(32, mul(32, i))), k) 322 | } 323 | } 324 | 325 | return result; 326 | } 327 | } 328 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/src/Vm.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2 <0.9.0; 3 | 4 | pragma experimental ABIEncoderV2; 5 | 6 | interface VmSafe { 7 | struct Log { 8 | bytes32[] topics; 9 | bytes data; 10 | } 11 | 12 | // Loads a storage slot from an address (who, slot) 13 | function load(address, bytes32) external returns (bytes32); 14 | // Signs data, (privateKey, digest) => (v, r, s) 15 | function sign(uint256, bytes32) external returns (uint8, bytes32, bytes32); 16 | // Gets the address for a given private key, (privateKey) => (address) 17 | function addr(uint256) external returns (address); 18 | // Gets the nonce of an account 19 | function getNonce(address) external returns (uint64); 20 | // Performs a foreign function call via the terminal, (stringInputs) => (result) 21 | function ffi(string[] calldata) external returns (bytes memory); 22 | // Sets environment variables, (name, value) 23 | function setEnv(string calldata, string calldata) external; 24 | // Reads environment variables, (name) => (value) 25 | function envBool(string calldata) external returns (bool); 26 | function envUint(string calldata) external returns (uint256); 27 | function envInt(string calldata) external returns (int256); 28 | function envAddress(string calldata) external returns (address); 29 | function envBytes32(string calldata) external returns (bytes32); 30 | function envString(string calldata) external returns (string memory); 31 | function envBytes(string calldata) external returns (bytes memory); 32 | // Reads environment variables as arrays, (name, delim) => (value[]) 33 | function envBool(string calldata, string calldata) external returns (bool[] memory); 34 | function envUint(string calldata, string calldata) external returns (uint256[] memory); 35 | function envInt(string calldata, string calldata) external returns (int256[] memory); 36 | function envAddress(string calldata, string calldata) external returns (address[] memory); 37 | function envBytes32(string calldata, string calldata) external returns (bytes32[] memory); 38 | function envString(string calldata, string calldata) external returns (string[] memory); 39 | function envBytes(string calldata, string calldata) external returns (bytes[] memory); 40 | // Records all storage reads and writes 41 | function record() external; 42 | // Gets all accessed reads and write slot from a recording session, for a given address 43 | function accesses(address) external returns (bytes32[] memory reads, bytes32[] memory writes); 44 | // Gets the _creation_ bytecode from an artifact file. Takes in the relative path to the json file 45 | function getCode(string calldata) external returns (bytes memory); 46 | // Gets the _deployed_ bytecode from an artifact file. Takes in the relative path to the json file 47 | function getDeployedCode(string calldata) external returns (bytes memory); 48 | // Labels an address in call traces 49 | function label(address, string calldata) external; 50 | // Using the address that calls the test contract, has the next call (at this call depth only) create a transaction that can later be signed and sent onchain 51 | function broadcast() external; 52 | // Has the next call (at this call depth only) create a transaction with the address provided as the sender that can later be signed and sent onchain 53 | function broadcast(address) external; 54 | // Has the next call (at this call depth only) create a transaction with the private key provided as the sender that can later be signed and sent onchain 55 | function broadcast(uint256) external; 56 | // Using the address that calls the test contract, has all subsequent calls (at this call depth only) create transactions that can later be signed and sent onchain 57 | function startBroadcast() external; 58 | // Has all subsequent calls (at this call depth only) create transactions with the address provided that can later be signed and sent onchain 59 | function startBroadcast(address) external; 60 | // Has all subsequent calls (at this call depth only) create transactions with the private key provided that can later be signed and sent onchain 61 | function startBroadcast(uint256) external; 62 | // Stops collecting onchain transactions 63 | function stopBroadcast() external; 64 | // Reads the entire content of file to string, (path) => (data) 65 | function readFile(string calldata) external returns (string memory); 66 | // Reads the entire content of file as binary. Path is relative to the project root. (path) => (data) 67 | function readFileBinary(string calldata) external returns (bytes memory); 68 | // Get the path of the current project root 69 | function projectRoot() external returns (string memory); 70 | // Reads next line of file to string, (path) => (line) 71 | function readLine(string calldata) external returns (string memory); 72 | // Writes data to file, creating a file if it does not exist, and entirely replacing its contents if it does. 73 | // (path, data) => () 74 | function writeFile(string calldata, string calldata) external; 75 | // Writes binary data to a file, creating a file if it does not exist, and entirely replacing its contents if it does. 76 | // Path is relative to the project root. (path, data) => () 77 | function writeFileBinary(string calldata, bytes calldata) external; 78 | // Writes line to file, creating a file if it does not exist. 79 | // (path, data) => () 80 | function writeLine(string calldata, string calldata) external; 81 | // Closes file for reading, resetting the offset and allowing to read it from beginning with readLine. 82 | // (path) => () 83 | function closeFile(string calldata) external; 84 | // Removes file. This cheatcode will revert in the following situations, but is not limited to just these cases: 85 | // - Path points to a directory. 86 | // - The file doesn't exist. 87 | // - The user lacks permissions to remove the file. 88 | // (path) => () 89 | function removeFile(string calldata) external; 90 | // Convert values to a string, (value) => (stringified value) 91 | function toString(address) external returns (string memory); 92 | function toString(bytes calldata) external returns (string memory); 93 | function toString(bytes32) external returns (string memory); 94 | function toString(bool) external returns (string memory); 95 | function toString(uint256) external returns (string memory); 96 | function toString(int256) external returns (string memory); 97 | // Convert values from a string, (string) => (parsed value) 98 | function parseBytes(string calldata) external returns (bytes memory); 99 | function parseAddress(string calldata) external returns (address); 100 | function parseUint(string calldata) external returns (uint256); 101 | function parseInt(string calldata) external returns (int256); 102 | function parseBytes32(string calldata) external returns (bytes32); 103 | function parseBool(string calldata) external returns (bool); 104 | // Record all the transaction logs 105 | function recordLogs() external; 106 | // Gets all the recorded logs, () => (logs) 107 | function getRecordedLogs() external returns (Log[] memory); 108 | // Derive a private key from a provided mnenomic string (or mnenomic file path) at the derivation path m/44'/60'/0'/0/{index} 109 | function deriveKey(string calldata, uint32) external returns (uint256); 110 | // Derive a private key from a provided mnenomic string (or mnenomic file path) at the derivation path {path}{index} 111 | function deriveKey(string calldata, string calldata, uint32) external returns (uint256); 112 | // Adds a private key to the local forge wallet and returns the address 113 | function rememberKey(uint256) external returns (address); 114 | // Given a string of JSON, return the ABI-encoded value of provided key 115 | // (stringified json, key) => (ABI-encoded data) 116 | // Read the note below! 117 | function parseJson(string calldata, string calldata) external returns (bytes memory); 118 | // Given a string of JSON, return it as ABI-encoded, (stringified json, key) => (ABI-encoded data) 119 | // Read the note below! 120 | function parseJson(string calldata) external returns (bytes memory); 121 | // Note: 122 | // ---- 123 | // In case the returned value is a JSON object, it's encoded as a ABI-encoded tuple. As JSON objects 124 | // don't have the notion of ordered, but tuples do, they JSON object is encoded with it's fields ordered in 125 | // ALPHABETICAL ordser. That means that in order to succesfully decode the tuple, we need to define a tuple that 126 | // encodes the fields in the same order, which is alphabetical. In the case of Solidity structs, they are encoded 127 | // as tuples, with the attributes in the order in which they are defined. 128 | // For example: json = { 'a': 1, 'b': 0xa4tb......3xs} 129 | // a: uint256 130 | // b: address 131 | // To decode that json, we need to define a struct or a tuple as follows: 132 | // struct json = { uint256 a; address b; } 133 | // If we defined a json struct with the opposite order, meaning placing the address b first, it would try to 134 | // decode the tuple in that order, and thus fail. 135 | 136 | // Returns the RPC url for the given alias 137 | function rpcUrl(string calldata) external returns (string memory); 138 | // Returns all rpc urls and their aliases `[alias, url][]` 139 | function rpcUrls() external returns (string[2][] memory); 140 | 141 | // If the condition is false, discard this run's fuzz inputs and generate new ones. 142 | function assume(bool) external; 143 | } 144 | 145 | interface Vm is VmSafe { 146 | // Sets block.timestamp (newTimestamp) 147 | function warp(uint256) external; 148 | // Sets block.height (newHeight) 149 | function roll(uint256) external; 150 | // Sets block.basefee (newBasefee) 151 | function fee(uint256) external; 152 | // Sets block.difficulty (newDifficulty) 153 | function difficulty(uint256) external; 154 | // Sets block.chainid 155 | function chainId(uint256) external; 156 | // Stores a value to an address' storage slot, (who, slot, value) 157 | function store(address, bytes32, bytes32) external; 158 | // Sets the nonce of an account; must be higher than the current nonce of the account 159 | function setNonce(address, uint64) external; 160 | // Sets the *next* call's msg.sender to be the input address 161 | function prank(address) external; 162 | // Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called 163 | function startPrank(address) external; 164 | // Sets the *next* call's msg.sender to be the input address, and the tx.origin to be the second input 165 | function prank(address, address) external; 166 | // Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called, and the tx.origin to be the second input 167 | function startPrank(address, address) external; 168 | // Resets subsequent calls' msg.sender to be `address(this)` 169 | function stopPrank() external; 170 | // Sets an address' balance, (who, newBalance) 171 | function deal(address, uint256) external; 172 | // Sets an address' code, (who, newCode) 173 | function etch(address, bytes calldata) external; 174 | // Expects an error on next call 175 | function expectRevert(bytes calldata) external; 176 | function expectRevert(bytes4) external; 177 | function expectRevert() external; 178 | // Prepare an expected log with (bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData). 179 | // Call this function, then emit an event, then call a function. Internally after the call, we check if 180 | // logs were emitted in the expected order with the expected topics and data (as specified by the booleans) 181 | function expectEmit(bool, bool, bool, bool) external; 182 | function expectEmit(bool, bool, bool, bool, address) external; 183 | // Mocks a call to an address, returning specified data. 184 | // Calldata can either be strict or a partial match, e.g. if you only 185 | // pass a Solidity selector to the expected calldata, then the entire Solidity 186 | // function will be mocked. 187 | function mockCall(address, bytes calldata, bytes calldata) external; 188 | // Mocks a call to an address with a specific msg.value, returning specified data. 189 | // Calldata match takes precedence over msg.value in case of ambiguity. 190 | function mockCall(address, uint256, bytes calldata, bytes calldata) external; 191 | // Clears all mocked calls 192 | function clearMockedCalls() external; 193 | // Expects a call to an address with the specified calldata. 194 | // Calldata can either be a strict or a partial match 195 | function expectCall(address, bytes calldata) external; 196 | // Expects a call to an address with the specified msg.value and calldata 197 | function expectCall(address, uint256, bytes calldata) external; 198 | // Sets block.coinbase (who) 199 | function coinbase(address) external; 200 | // Snapshot the current state of the evm. 201 | // Returns the id of the snapshot that was created. 202 | // To revert a snapshot use `revertTo` 203 | function snapshot() external returns (uint256); 204 | // Revert the state of the evm to a previous snapshot 205 | // Takes the snapshot id to revert to. 206 | // This deletes the snapshot and all snapshots taken after the given snapshot id. 207 | function revertTo(uint256) external returns (bool); 208 | // Creates a new fork with the given endpoint and block and returns the identifier of the fork 209 | function createFork(string calldata, uint256) external returns (uint256); 210 | // Creates a new fork with the given endpoint and the _latest_ block and returns the identifier of the fork 211 | function createFork(string calldata) external returns (uint256); 212 | // Creates a new fork with the given endpoint and at the block the given transaction was mined in, and replays all transaction mined in the block before the transaction 213 | function createFork(string calldata, bytes32) external returns (uint256); 214 | // Creates _and_ also selects a new fork with the given endpoint and block and returns the identifier of the fork 215 | function createSelectFork(string calldata, uint256) external returns (uint256); 216 | // Creates _and_ also selects new fork with the given endpoint and at the block the given transaction was mined in, and replays all transaction mined in the block before the transaction 217 | function createSelectFork(string calldata, bytes32) external returns (uint256); 218 | // Creates _and_ also selects a new fork with the given endpoint and the latest block and returns the identifier of the fork 219 | function createSelectFork(string calldata) external returns (uint256); 220 | // Takes a fork identifier created by `createFork` and sets the corresponding forked state as active. 221 | function selectFork(uint256) external; 222 | /// Returns the currently active fork 223 | /// Reverts if no fork is currently active 224 | function activeFork() external returns (uint256); 225 | // Updates the currently active fork to given block number 226 | // This is similar to `roll` but for the currently active fork 227 | function rollFork(uint256) external; 228 | // Updates the currently active fork to given transaction 229 | // this will `rollFork` with the number of the block the transaction was mined in and replays all transaction mined before it in the block 230 | function rollFork(bytes32) external; 231 | // Updates the given fork to given block number 232 | function rollFork(uint256 forkId, uint256 blockNumber) external; 233 | // Updates the given fork to block number of the given transaction and replays all transaction mined before it in the block 234 | function rollFork(uint256 forkId, bytes32 transaction) external; 235 | // Marks that the account(s) should use persistent storage across fork swaps in a multifork setup 236 | // Meaning, changes made to the state of this account will be kept when switching forks 237 | function makePersistent(address) external; 238 | function makePersistent(address, address) external; 239 | function makePersistent(address, address, address) external; 240 | function makePersistent(address[] calldata) external; 241 | // Revokes persistent status from the address, previously added via `makePersistent` 242 | function revokePersistent(address) external; 243 | function revokePersistent(address[] calldata) external; 244 | // Returns true if the account is marked as persistent 245 | function isPersistent(address) external returns (bool); 246 | // In forking mode, explicitly grant the given address cheatcode access 247 | function allowCheatcodes(address) external; 248 | // Fetches the given transaction from the active fork and executes it on the current state 249 | function transact(bytes32 txHash) external; 250 | // Fetches the given transaction from the given fork and executes it on the current state 251 | function transact(uint256 forkId, bytes32 txHash) external; 252 | } 253 | -------------------------------------------------------------------------------- /packages/foundry/lib/forge-std/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(" Expected", b); 432 | emit log_named_string(" Actual", a); 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", b); 459 | emit log_named_bytes(" Actual", a); 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 | --------------------------------------------------------------------------------