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 |
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 • [](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 |
--------------------------------------------------------------------------------