├── .cruft.json ├── .dockerignore ├── .flake8 ├── .github ├── actions │ └── with-docker │ │ └── action.yml └── workflows │ ├── Dockerfile │ ├── kontrol-push-fixed-deps.yml │ ├── kontrol-push-unfixed-deps.yml │ ├── master-push.yml │ ├── release.yml │ ├── test-pr.yml │ ├── update-expected-output.yml │ └── update-version.yml ├── .gitignore ├── .gitmodules ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── deps ├── k_release ├── kevm_release ├── pyproject-build-systems ├── uv2nix └── z3 ├── docs ├── 2023-10-10-running-rpc-server-manually.md └── external-computation │ ├── .gitignore │ ├── README.md │ ├── foundry.toml │ ├── script │ └── Counter.s.sol │ ├── src │ └── Counter.sol │ └── test │ ├── Counter.t.sol │ └── kontrol │ ├── proofs │ ├── Counter.k.sol │ └── utils │ │ ├── InitialState.sol │ │ ├── InitialStateCode.sol │ │ └── Interfaces.sol │ ├── scripts │ ├── json │ │ └── clean_json.py │ └── record-state-diff.sh │ └── state-diff │ ├── proof-initialization.sol │ └── record-state-diff │ ├── LibStateDiff.sol │ └── RecordStateDiff.sol ├── flake.lock ├── flake.nix ├── funding.json ├── nix ├── kontrol-pyk │ ├── build-systems-overlay.nix │ └── default.nix ├── kontrol-source │ └── default.nix └── kontrol │ └── default.nix ├── package ├── test-package.sh ├── test-project │ ├── foundry.toml │ └── test │ │ └── Simple.t.sol ├── version └── version.sh ├── pyproject.toml ├── src ├── kontrol │ ├── __init__.py │ ├── __main__.py │ ├── cli.py │ ├── display.py │ ├── foundry.py │ ├── kdist │ │ ├── __init__.py │ │ ├── assert.md │ │ ├── cheatcodes.md │ │ ├── foundry.md │ │ ├── hevm.md │ │ ├── keccak.md │ │ ├── kontrol.md │ │ ├── kontrol_lemmas.md │ │ ├── no_code_size_checks.md │ │ ├── no_stack_checks.md │ │ ├── plugin.py │ │ ├── trace.md │ │ └── utils.py │ ├── kompile.py │ ├── options.py │ ├── prove.py │ ├── py.typed │ ├── solc.py │ ├── solc_to_k.py │ ├── state_record.py │ └── utils.py └── tests │ ├── __init__.py │ ├── conftest.py │ ├── integration │ ├── __init__.py │ ├── conftest.py │ ├── test-data │ │ ├── accesses.json │ │ ├── cse-lemmas.k │ │ ├── dumpState.json │ │ ├── end-to-end-prove-all │ │ ├── end-to-end-prove-show │ │ ├── end-to-end-prove-skip │ │ ├── foundry-bmc-all │ │ ├── foundry-bmc-skip │ │ ├── foundry-dependency-all │ │ ├── foundry-dependency-skip │ │ ├── foundry-fail │ │ ├── foundry-init-code │ │ ├── foundry-init-code-skip │ │ ├── foundry-minimize │ │ ├── foundry-minimize-merge │ │ ├── foundry-prove-all │ │ ├── foundry-prove-skip │ │ ├── foundry-prove-skip-legacy │ │ ├── foundry-prove-with-gas │ │ ├── foundry-show │ │ ├── foundry-trace-all │ │ ├── foundry-trace-skip │ │ ├── foundry │ │ │ ├── foundry.toml │ │ │ ├── src │ │ │ │ ├── ArithmeticContract.sol │ │ │ │ ├── Branches.sol │ │ │ │ ├── ContractToRecordState.sol │ │ │ │ ├── EmitContract.sol │ │ │ │ ├── LoadStateDiff.sol │ │ │ │ ├── LoadStateDiffCode.sol │ │ │ │ ├── LoadStateDump.sol │ │ │ │ ├── LoadStateDumpCode.sol │ │ │ │ ├── Mock.sol │ │ │ │ ├── MyIERC20.sol │ │ │ │ ├── MyToken.sol │ │ │ │ ├── OwnerOnlyUp.sol │ │ │ │ ├── Portal.sol │ │ │ │ ├── Prank.sol │ │ │ │ ├── Safe.sol │ │ │ │ ├── TestNumber.sol │ │ │ │ ├── Token.sol │ │ │ │ ├── cse │ │ │ │ │ ├── Binary.sol │ │ │ │ │ ├── OperatorInterfaces.sol │ │ │ │ │ ├── Unary.sol │ │ │ │ │ └── WETH9.sol │ │ │ │ └── duplicates │ │ │ │ │ ├── 1 │ │ │ │ │ └── DuplicateName.sol │ │ │ │ │ └── 2 │ │ │ │ │ └── DuplicateName.sol │ │ │ └── test │ │ │ │ ├── AccountParamsTest.t.sol │ │ │ │ ├── AddrTest.t.sol │ │ │ │ ├── AllowChangesTest.t.sol │ │ │ │ ├── Ambiguous.t.sol │ │ │ │ ├── Arithmetic.t.sol │ │ │ │ ├── ArithmeticCall.t.sol │ │ │ │ ├── AssumeTest.t.sol │ │ │ │ ├── BMCBound.t.sol │ │ │ │ ├── BMCLoops.t.sol │ │ │ │ ├── BlockParamsTest.t.sol │ │ │ │ ├── BroadcastTest.t.sol │ │ │ │ ├── CSE.t.sol │ │ │ │ ├── CallableStorageTest.t.sol │ │ │ │ ├── ConstructorTest.t.sol │ │ │ │ ├── Contract.t.sol │ │ │ │ ├── ContractBTest.t.sol │ │ │ │ ├── ContractFieldTest.t.sol │ │ │ │ ├── CopyStorage.t.sol │ │ │ │ ├── CounterTest.t.sol │ │ │ │ ├── DynamicTypes.t.sol │ │ │ │ ├── EmitContractTest.t.sol │ │ │ │ ├── Enum.t.sol │ │ │ │ ├── EnvTest.t.sol │ │ │ │ ├── ExpectCallTest.t.sol │ │ │ │ ├── ExpectRevertTest.t.sol │ │ │ │ ├── ExternalLibTest.t.sol │ │ │ │ ├── ExternalNestedLibraryTest.t.sol │ │ │ │ ├── FfiTest.t.sol │ │ │ │ ├── FilesTest.t.sol │ │ │ │ ├── ForkTest.t.sol │ │ │ │ ├── FreshBytes.t.sol │ │ │ │ ├── FreshInt.t.sol │ │ │ │ ├── GasTest.t.sol │ │ │ │ ├── GetCodeTest.t.sol │ │ │ │ ├── HevmTests.t.sol │ │ │ │ ├── ImmutableVarsTest.t.sol │ │ │ │ ├── InitCode.t.sol │ │ │ │ ├── InitCodeBranch.t.sol │ │ │ │ ├── InterfaceTagTest.sol │ │ │ │ ├── LabelTest.t.sol │ │ │ │ ├── Loops.t.sol │ │ │ │ ├── Merge.t.sol │ │ │ │ ├── MergeKCFGTest.t.sol │ │ │ │ ├── MethodDisambiguate.t.sol │ │ │ │ ├── MockCallTest.t.sol │ │ │ │ ├── MockFunction.t.sol │ │ │ │ ├── NestedArrayStructs.t.sol │ │ │ │ ├── NestedStructs.t.sol │ │ │ │ ├── NoImports.t.sol │ │ │ │ ├── OwnerOnlyUpTest.t.sol │ │ │ │ ├── PlainPrankTest.t.sol │ │ │ │ ├── PortalTest.sol │ │ │ │ ├── PrankTest.t.sol │ │ │ │ ├── Preconditions.t.sol │ │ │ │ ├── RecordLogsTest.t.sol │ │ │ │ ├── SafeTest.t.sol │ │ │ │ ├── SetUp2Test.t.sol │ │ │ │ ├── SetUpDeploy.t.sol │ │ │ │ ├── SetUpTest.t.sol │ │ │ │ ├── SignTest.t.sol │ │ │ │ ├── Simple.t.sol │ │ │ │ ├── SnapshotTest.t.sol │ │ │ │ ├── StoreTest.t.sol │ │ │ │ ├── SymbolicStorageTest.t.sol │ │ │ │ ├── ToStringTest.t.sol │ │ │ │ ├── TypeTest.t.sol │ │ │ │ ├── file.txt │ │ │ │ ├── myscript.sh │ │ │ │ ├── nested │ │ │ │ └── SimpleNested.t.sol │ │ │ │ └── script.sh │ │ ├── lemmas.k │ │ ├── pausability-lemmas.k │ │ ├── show │ │ │ ├── AccountParamsTest.testDealConcrete().trace.expected │ │ │ ├── AddConst.applyOp(uint256).cse.expected │ │ │ ├── AddrTest.test_addr_true().trace.expected │ │ │ ├── ArithmeticCallTest.test_double_add(uint256,uint256).cse.expected │ │ │ ├── ArithmeticCallTest.test_double_add(uint256,uint256).expected │ │ │ ├── ArithmeticCallTest.test_double_add_double_sub(uint256,uint256).cse.expected │ │ │ ├── ArithmeticCallTest.test_double_add_double_sub(uint256,uint256).expected │ │ │ ├── ArithmeticCallTest.test_double_add_sub_external(uint256,uint256,uint256).cse.expected │ │ │ ├── ArithmeticContract.add(uint256,uint256).cse.expected │ │ │ ├── ArithmeticContract.add_sub_external(uint256,uint256,uint256).cse.expected │ │ │ ├── AssertTest.checkFail_assert_false().expected │ │ │ ├── AssertTest.testFail_assert_true().expected │ │ │ ├── AssertTest.testFail_expect_revert().expected │ │ │ ├── AssertTest.test_assert_false().expected │ │ │ ├── AssertTest.test_assert_true().expected │ │ │ ├── AssertTest.test_assert_true().trace.expected │ │ │ ├── AssertTest.test_failing_branch(uint256).expected │ │ │ ├── AssertTest.test_revert_branch(uint256,uint256).expected │ │ │ ├── AssumeTest.testFail_assume_false(uint256,uint256).expected │ │ │ ├── AssumeTest.testFail_assume_true(uint256,uint256).expected │ │ │ ├── AssumeTest.test_assume_false(uint256,uint256).expected │ │ │ ├── BMCBoundTest.testBound().expected │ │ │ ├── BlockParamsTest.testWarp(uint256).trace.expected │ │ │ ├── CSETest.test_add_const(uint256,uint256).cse.expected │ │ │ ├── CSETest.test_identity(uint256,uint256).cse.expected │ │ │ ├── CallableStorageContract.str().cse.expected │ │ │ ├── CallableStorageTest.test_str().cse.expected │ │ │ ├── ConstructorTest.init.cse.expected │ │ │ ├── ConstructorTest.test_contract_call().cse.expected │ │ │ ├── ContractFieldTest.testEscrowToken().cse.expected │ │ │ ├── Enum.enum_argument_range(uint8).cse.expected │ │ │ ├── Enum.enum_storage_range().cse.expected │ │ │ ├── Enum.init.cse.expected │ │ │ ├── ForgetBranchTest.test_forgetBranch(uint256).expected │ │ │ ├── Identity.applyOp(uint256).cse.expected │ │ │ ├── Identity.identity(uint256).cse.expected │ │ │ ├── ImmutableVarsTest.test_run_deployment(uint256).expected │ │ │ ├── ImportedContract.add(uint256).cse.expected │ │ │ ├── ImportedContract.count().cse.expected │ │ │ ├── ImportedContract.init.cse.expected │ │ │ ├── ImportedContract.set(uint256).cse.expected │ │ │ ├── InterfaceTagTest.testInterface().cse.expected │ │ │ ├── RandomVarTest.test_custom_names().expected │ │ │ ├── SetUpDeployTest.test_extcodesize().expected │ │ │ ├── StaticCallContract.set(uint256).cse.expected │ │ │ ├── TGovernance.getEscrowTokenTotalSupply().cse.expected │ │ │ ├── foundry.k.expected │ │ │ ├── gas-abstraction.expected │ │ │ ├── merge-loop-heads.expected │ │ │ ├── minimized │ │ │ │ ├── AssertTest.testFail_expect_revert().expected │ │ │ │ ├── AssertTest.test_assert_false().expected │ │ │ │ ├── AssertTest.test_failing_branch(uint256).expected │ │ │ │ ├── AssertTest.test_revert_branch(uint256,uint256).expected │ │ │ │ └── MergeKCFGTest.test_branch_merge(uint256,uint256,bool).expected │ │ │ ├── node-refutation.expected │ │ │ └── split-node.expected │ │ ├── src │ │ │ ├── AllowCalls.t.sol │ │ │ ├── ForgetBranch.t.sol │ │ │ ├── RandomVar.t.sol │ │ │ ├── TransientStorage.t.sol │ │ │ └── Unit.t.sol │ │ ├── symbolic-bytes-lemmas.k │ │ └── xor-lemmas.k │ ├── test_foundry_prove.py │ ├── test_hevm_prove.py │ ├── test_kontrol.py │ ├── test_kontrol_cse.py │ ├── test_tracing.py │ └── utils.py │ ├── profiling │ ├── __init__.py │ ├── test-data │ │ └── foundry │ │ │ ├── foundry.toml │ │ │ └── test │ │ │ └── Simple.t.sol │ ├── test_foundry_prove.py │ └── utils.py │ ├── unit │ ├── __init__.py │ ├── test-data │ │ ├── accesses.json │ │ ├── foundry-list │ │ │ ├── apr_proofs │ │ │ │ ├── test%AssertTest.checkFail_assert_false():0 │ │ │ │ │ ├── kcfg │ │ │ │ │ │ ├── kcfg.json │ │ │ │ │ │ └── nodes │ │ │ │ │ │ │ ├── 1.json │ │ │ │ │ │ │ ├── 3.json │ │ │ │ │ │ │ ├── 4.json │ │ │ │ │ │ │ ├── 5.json │ │ │ │ │ │ │ └── 6.json │ │ │ │ │ └── proof.json │ │ │ │ ├── test%AssertTest.setUp():0 │ │ │ │ │ ├── kcfg │ │ │ │ │ │ ├── kcfg.json │ │ │ │ │ │ └── nodes │ │ │ │ │ │ │ ├── 1.json │ │ │ │ │ │ │ ├── 2.json │ │ │ │ │ │ │ └── 3.json │ │ │ │ │ └── proof.json │ │ │ │ ├── test%AssertTest.testFail_assert_true():0 │ │ │ │ │ ├── kcfg │ │ │ │ │ │ ├── kcfg.json │ │ │ │ │ │ └── nodes │ │ │ │ │ │ │ ├── 1.json │ │ │ │ │ │ │ ├── 3.json │ │ │ │ │ │ │ ├── 4.json │ │ │ │ │ │ │ ├── 5.json │ │ │ │ │ │ │ └── 6.json │ │ │ │ │ └── proof.json │ │ │ │ ├── test%AssertTest.test_assert_false():0 │ │ │ │ │ ├── kcfg │ │ │ │ │ │ ├── kcfg.json │ │ │ │ │ │ └── nodes │ │ │ │ │ │ │ ├── 1.json │ │ │ │ │ │ │ ├── 3.json │ │ │ │ │ │ │ ├── 4.json │ │ │ │ │ │ │ ├── 5.json │ │ │ │ │ │ │ └── 6.json │ │ │ │ │ └── proof.json │ │ │ │ └── test%AssertTest.test_assert_true():0 │ │ │ │ │ ├── kcfg │ │ │ │ │ ├── kcfg.json │ │ │ │ │ └── nodes │ │ │ │ │ │ ├── 1.json │ │ │ │ │ │ ├── 3.json │ │ │ │ │ │ ├── 4.json │ │ │ │ │ │ ├── 5.json │ │ │ │ │ │ └── 6.json │ │ │ │ │ └── proof.json │ │ │ └── foundry-list.expected │ │ └── kontrol_test.toml │ ├── test_foundry_list.py │ ├── test_foundry_prove.py │ ├── test_get_test_id.py │ ├── test_latest_proof_version.py │ ├── test_solc_to_k.py │ ├── test_toml_args.py │ └── utils.py │ └── utils.py └── uv.lock /.cruft.json: -------------------------------------------------------------------------------- 1 | { 2 | "template": "https://github.com/runtimeverification/python-project-template.git", 3 | "commit": "601d5e2a0e8a98c87dcb1ae694d22d76d0114e01", 4 | "checkout": null, 5 | "context": { 6 | "cookiecutter": { 7 | "project_name": "Kontrol", 8 | "project_slug": "kontrol", 9 | "package_name": "kontrol", 10 | "version": "0.1.0", 11 | "description": "Foundry integration for KEVM", 12 | "author_name": "Runtime Verification, Inc.", 13 | "author_email": "contact@runtimeverification.com", 14 | "_template": "https://github.com/runtimeverification/python-project-template.git" 15 | } 16 | }, 17 | "directory": null 18 | } 19 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | Dockerfile 2 | .dockerignore 3 | .git 4 | .github 5 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 120 3 | extend-select = B9, TC1 4 | extend-ignore = B950,E,W1,W2,W3,W4,W5 5 | per-file-ignores = 6 | */__init__.py: F401 7 | type-checking-strict = true 8 | exclude = 9 | src/tests/integration/test-data 10 | -------------------------------------------------------------------------------- /.github/actions/with-docker/action.yml: -------------------------------------------------------------------------------- 1 | name: 'With Docker' 2 | description: 'Run a given stage with Docker Image' 3 | inputs: 4 | container-name: 5 | description: 'Docker container name to use' 6 | type: string 7 | required: true 8 | tag-name: 9 | description: 'Docker image tag to use' 10 | type: string 11 | required: false 12 | default: runtimeverificationinc/kontrol 13 | subdir: 14 | description: 'Subdirectory where code is cloned.' 15 | required: false 16 | type: string 17 | default: './' 18 | os: 19 | description: 'OS to setup Docker for.' 20 | required: false 21 | type: string 22 | default: 'ubuntu' 23 | distro: 24 | description: 'Distribution to setup Docker for.' 25 | required: false 26 | type: string 27 | default: 'jammy' 28 | llvm: 29 | description: 'LLVM version to use.' 30 | required: false 31 | type: number 32 | default: 14 33 | dockerfile: 34 | description: 'Hardcode the path of the dockerfile to use.' 35 | required: false 36 | type: string 37 | default: '.github/workflows/Dockerfile' 38 | runs: 39 | using: 'composite' 40 | steps: 41 | - name: 'Set up Docker' 42 | shell: bash {0} 43 | run: | 44 | set -euxo pipefail 45 | 46 | CONTAINER_NAME=${{ inputs.container-name }} 47 | SUBDIR=${{ inputs.subdir }} 48 | BASE_OS=${{ inputs.os }} 49 | BASE_DISTRO=${{ inputs.distro }} 50 | DOCKERFILE=${{ inputs.dockerfile }} 51 | LLVM_VERSION=${{ inputs.llvm }} 52 | TAG_NAME=${{ inputs.tag-name }} 53 | 54 | USER=github-user 55 | GROUP=${USER} 56 | Z3_VERSION=$(cat deps/z3) 57 | K_VERSION=$(cat deps/k_release) 58 | USER_ID=1000 59 | GROUP_ID=${USER_ID} 60 | 61 | docker build . --file ${DOCKERFILE} \ 62 | --tag ${TAG_NAME} \ 63 | --build-arg USER_ID=${USER_ID} \ 64 | --build-arg GROUP_ID=${GROUP_ID} \ 65 | --build-arg USER=${USER} \ 66 | --build-arg GROUP=${GROUP} \ 67 | --build-arg BASE_DISTRO=${BASE_DISTRO} \ 68 | --build-arg K_VERSION=${K_VERSION} \ 69 | --build-arg Z3_VERSION=${Z3_VERSION} \ 70 | --build-arg LLVM_VERSION=${LLVM_VERSION} 71 | 72 | docker run \ 73 | --name ${CONTAINER_NAME} \ 74 | --rm \ 75 | --interactive \ 76 | --tty \ 77 | --detach \ 78 | --user root \ 79 | --workdir /home/${USER}/workspace \ 80 | ${TAG_NAME} 81 | 82 | docker cp . ${CONTAINER_NAME}:/home/${USER}/workspace 83 | docker exec ${CONTAINER_NAME} chown -R ${USER}:${GROUP} /home/${USER} 84 | -------------------------------------------------------------------------------- /.github/workflows/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG Z3_VERSION 2 | ARG K_VERSION 3 | ARG BASE_DISTRO 4 | ARG LLVM_VERSION 5 | 6 | FROM ghcr.io/foundry-rs/foundry:rc-1 as FOUNDRY 7 | 8 | ARG Z3_VERSION 9 | FROM runtimeverificationinc/z3:ubuntu-jammy-${Z3_VERSION} as Z3 10 | 11 | ARG K_VERSION 12 | FROM runtimeverificationinc/kframework-k:ubuntu-jammy-${K_VERSION} 13 | 14 | COPY --from=FOUNDRY /usr/local/bin/forge /usr/local/bin/forge 15 | COPY --from=FOUNDRY /usr/local/bin/anvil /usr/local/bin/anvil 16 | COPY --from=FOUNDRY /usr/local/bin/cast /usr/local/bin/cast 17 | 18 | COPY --from=Z3 /usr/bin/z3 /usr/bin/z3 19 | 20 | ARG LLVM_VERSION 21 | 22 | RUN apt-get update \ 23 | && apt-get upgrade --yes \ 24 | && apt-get install --yes \ 25 | cargo \ 26 | clang-${LLVM_VERSION} \ 27 | cmake \ 28 | curl \ 29 | debhelper \ 30 | libboost-test-dev \ 31 | libcrypto++-dev \ 32 | libsecp256k1-dev \ 33 | libssl-dev \ 34 | libyaml-dev \ 35 | llvm-${LLVM_VERSION}-dev \ 36 | llvm-${LLVM_VERSION}-tools \ 37 | maven \ 38 | python3 \ 39 | python3-pip 40 | 41 | ARG USER=user 42 | ARG GROUP 43 | ARG USER_ID 44 | ARG GROUP_ID 45 | RUN groupadd -g ${GROUP_ID} ${GROUP} && useradd -m -u ${USER_ID} -s /bin/sh -g ${GROUP} ${USER} 46 | 47 | USER ${USER}:${GROUP} 48 | RUN mkdir /home/${USER}/workspace 49 | WORKDIR /home/${USER}/workspace 50 | 51 | ENV PATH=/home/${USER}/.cargo/bin:/home/${USER}/.local/bin:/usr/local/bin/:${PATH} 52 | 53 | RUN curl -LsSf https://astral.sh/uv/0.7.2/install.sh | sh && uv --version 54 | 55 | RUN cargo install svm-rs --version 0.3.0 --locked \ 56 | && svm install 0.8.13 \ 57 | && solc --version 58 | -------------------------------------------------------------------------------- /.github/workflows/kontrol-push-fixed-deps.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: 'Push Kontrol w/ FIXED Dependencies' 3 | on: 4 | workflow_dispatch: 5 | 6 | inputs: 7 | kontrol_branch: 8 | description: "Branch of Kontrol to use to build the Docker image" 9 | required: true 10 | 11 | jobs: 12 | dockerhub: 13 | name: 'Build and Publish Docker Image' 14 | runs-on: [self-hosted, linux, normal] 15 | steps: 16 | - name: 'Check out code' 17 | uses: actions/checkout@v4 18 | with: 19 | ref: ${{ github.event.inputs.kontrol_branch}} 20 | fetch-depth: 0 21 | 22 | - name: 'Set environment' 23 | run: | 24 | KONTROL_VERSION=$(cat package/version) 25 | echo "CONTAINER_NAME=kontrol-ci-docker-${GITHUB_SHA}" >> ${GITHUB_ENV} 26 | BRANCH_NAME="${{ github.event.inputs.kontrol_branch }}" 27 | SANITIZED_BRANCH_NAME=$(echo "${BRANCH_NAME}" | tr '/' '-' | tr -cd '[:alnum:]-_.') 28 | GHCR_TAG=ghcr.io/runtimeverification/kontrol/kontrol-custom:ubuntu-jammy-${SANITIZED_BRANCH_NAME} 29 | echo "GHCR_TAG=${GHCR_TAG}" >> ${GITHUB_ENV} 30 | echo "DOCKER_USER=user" >> ${GITHUB_ENV} 31 | echo "DOCKER_GROUP=user" >> ${GITHUB_ENV} 32 | echo "FOUNDRY_ROOT=/home/user/foundry" >> ${GITHUB_ENV} 33 | 34 | - name: 'Build Docker image' 35 | run: | 36 | K_VERSION=$(cat deps/k_release) 37 | Z3_VERSION=$(cat deps/z3) 38 | docker build . --no-cache --tag ${GHCR_TAG} --build-arg K_VERSION=${K_VERSION} --build-arg Z3_VERSION=${Z3_VERSION} 39 | 40 | - name: 'Run Docker image' 41 | run: | 42 | docker run \ 43 | --name ${CONTAINER_NAME} \ 44 | --rm \ 45 | --interactive \ 46 | --tty \ 47 | --detach \ 48 | --user root \ 49 | ${GHCR_TAG} 50 | 51 | docker cp src/tests/integration/test-data/foundry ${CONTAINER_NAME}:${FOUNDRY_ROOT} 52 | docker exec ${CONTAINER_NAME} chown -R ${DOCKER_USER}:${DOCKER_GROUP} ${FOUNDRY_ROOT} 53 | 54 | - name: 'Run forge build' 55 | run: | 56 | docker exec --user ${DOCKER_USER} --workdir ${FOUNDRY_ROOT} ${CONTAINER_NAME} forge install --no-git foundry-rs/forge-std@75f1746 57 | docker exec --user ${DOCKER_USER} --workdir ${FOUNDRY_ROOT} ${CONTAINER_NAME} forge install --no-git runtimeverification/kontrol-cheatcodes@a5dd4b0 58 | docker exec --user ${DOCKER_USER} --workdir ${FOUNDRY_ROOT} ${CONTAINER_NAME} forge build 59 | 60 | - name: 'Run kontrol build' 61 | run: docker exec --user ${DOCKER_USER} --workdir ${FOUNDRY_ROOT} ${CONTAINER_NAME} kontrol build -O2 62 | 63 | - name: 'Run kontrol prove' 64 | run: docker exec --user ${DOCKER_USER} --workdir ${FOUNDRY_ROOT} ${CONTAINER_NAME} kontrol prove --match-test 'AssertTest.test_assert_true()' 65 | 66 | - name: 'Run kontrol show' 67 | run: docker exec --user ${DOCKER_USER} --workdir ${FOUNDRY_ROOT} ${CONTAINER_NAME} kontrol show 'AssertTest.test_assert_true()' 68 | 69 | - name: 'Tear Down Docker' 70 | if: always() 71 | run: | 72 | docker stop --time=0 ${CONTAINER_NAME} 73 | 74 | - name: 'Push Docker Image to GitHub Packages' 75 | run: | 76 | echo ${{ secrets.DOCKERHUB_PASSWORD }} | docker login -u ${{ vars.DOCKERHUB_USERNAME }} --password-stdin 77 | echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin 78 | docker push ${GHCR_TAG} 79 | 80 | 81 | -------------------------------------------------------------------------------- /.github/workflows/kontrol-push-unfixed-deps.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: 'Push Kontrol w/ Dependencies' 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | kontrol-version: 7 | description: 'Branch/Tag to use for Kontrol' 8 | required: false 9 | default: '' 10 | kevm-version: 11 | description: 'SHA to use for KEVM' 12 | required: false 13 | default: '' 14 | k-version: 15 | description: 'SHA to use for K' 16 | required: false 17 | default: '' 18 | llvm-version: 19 | description: 'SHA to use for LLVM Backend' 20 | required: false 21 | default: '' 22 | haskell-version: 23 | description: 'SHA to use for Haskell Backend' 24 | required: false 25 | default: '' 26 | permissions: 27 | packages: write 28 | 29 | jobs: 30 | build-kontrol: 31 | runs-on: [self-hosted, normal] 32 | steps: 33 | - name: 'Login to GitHub Container Registry' 34 | uses: docker/login-action@v2 35 | with: 36 | registry: ghcr.io 37 | username: ${{ github.actor }} 38 | password: ${{ secrets.GITHUB_TOKEN }} 39 | - name: 'Build Kontrol' 40 | shell: bash 41 | run: | 42 | set -o pipefail 43 | docker run --env GH_TOKEN=${{ secrets.GITHUB_TOKEN }} --rm -it --detach --name kontrol-build-with-kup-${{ github.run_id }} ghcr.io/runtimeverification/kup:latest 44 | if [ -n "${{ inputs.kontrol-version }}" ]; then 45 | KONTROL_OVERRIDE="--version ${{ inputs.kontrol-version }}" 46 | fi 47 | if [ -n "${{ inputs.kevm-version }}" ]; then 48 | KEVM_OVERRIDE="--override kevm ${{ inputs.kevm-version }}" 49 | fi 50 | if [ -n "${{ inputs.k-version }}" ]; then 51 | K_OVERRIDE="--override kevm/k-framework ${{ inputs.k-version }}" 52 | fi 53 | if [ -n "${{ inputs.llvm-version }}" ]; then 54 | LLVM_OVERRIDE="--override kevm/k-framework/llvm-backend ${{ inputs.llvm-version }}" 55 | fi 56 | if [ -n "${{ inputs.haskell-version }}" ]; then 57 | HASKELL_OVERRIDE="--override kevm/k-framework/haskell-backend ${{ inputs.haskell-version }}" 58 | fi 59 | docker exec kontrol-build-with-kup-${{ github.run_id }} /bin/bash --login -c "kup install kontrol ${KONTROL_OVERRIDE} ${KEVM_OVERRIDE} ${K_OVERRIDE} ${LLVM_OVERRIDE} ${HASKELL_OVERRIDE}" 60 | docker exec kontrol-build-with-kup-${{ github.run_id }} /bin/bash --login -c "kup list kontrol --inputs" >> versions.out 61 | docker commit kontrol-build-with-kup-${{ github.run_id }} ghcr.io/runtimeverification/kontrol-custom:${{ github.run_id }} 62 | docker push ghcr.io/runtimeverification/kontrol-custom:${{ github.run_id }} 63 | - name: 'Publish Versions to Artifacts' 64 | uses: actions/upload-artifact@v4 65 | with: 66 | name: Versions 67 | path: versions.out 68 | - name: 'Publish Image Name to Workflow Summary' 69 | run: | 70 | echo "Image Name: ghcr.io/runtimeverification/kontrol-custom:${{ github.run_id }}" >> $GITHUB_STEP_SUMMARY 71 | - name: 'Tear down Docker' 72 | if: always() 73 | run: | 74 | docker stop --time=0 kontrol-build-with-kup-${{ github.run_id }} 75 | -------------------------------------------------------------------------------- /.github/workflows/master-push.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: 'Bump Release' 3 | on: 4 | push: 5 | branches: 6 | - 'master' 7 | concurrency: 8 | group: ${{ github.workflow }}-${{ github.ref }} 9 | cancel-in-progress: true 10 | 11 | jobs: 12 | version-bump: 13 | name: 'Version Bump and Start Release' 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: 'Check out code' 17 | uses: actions/checkout@v4 18 | with: 19 | token: ${{ secrets.JENKINS_GITHUB_PAT }} 20 | # fetch-depth 0 means deep clone the repo 21 | fetch-depth: 0 22 | - name: 'Configure GitHub user' 23 | run: | 24 | git config user.name rv-jenkins 25 | git config user.email devops@runtimeverification.com 26 | - name: 'Update version' 27 | run: | 28 | # Check out the release branch and create it if it doesn't exist 29 | git checkout -B release origin/release 30 | 31 | # Get the common ancestor commit between master and release branches 32 | old_master="$(git merge-base origin/master origin/release)" 33 | 34 | # Get the latest commit hash on the master branch 35 | new_master="$(git rev-parse origin/master)" 36 | 37 | # Check if there are changes in the package/version file between the common ancestor and the latest master commit 38 | if git diff --exit-code ${old_master} ${new_master} -- package/version; then 39 | # If there are no changes, bump the version based on the current version in master 40 | git merge --no-edit origin/master 41 | ./package/version.sh bump 42 | else 43 | # If there are changes, merge master into release with 'theirs' strategy to resolve conflicts 44 | git merge --no-edit --strategy-option=theirs origin/master 45 | fi 46 | 47 | # Substitute the version in the package/version file 48 | ./package/version.sh sub 49 | 50 | # Add changes to the staging area and commit them if there are any changes 51 | if git add --update && git commit --no-edit --allow-empty --message "Set Version: $(cat package/version)"; then 52 | # Push the changes to the release branch -- Trigger the Release Process and Testing 53 | git push origin release 54 | git tag "release-$(cat package/version)" origin/master 55 | git push origin "release-$(cat package/version)" 56 | fi 57 | -------------------------------------------------------------------------------- /.github/workflows/update-expected-output.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: 'Update Expected Output' 3 | on: 4 | workflow_dispatch: 5 | 6 | concurrency: 7 | group: ${{ github.workflow }}-${{ github.ref }} 8 | cancel-in-progress: true 9 | jobs: 10 | update-output: 11 | if: github.ref != 'refs/heads/master' 12 | name: 'Update Kontrol expected output' 13 | runs-on: [self-hosted, linux, normal, fast] 14 | timeout-minutes: 180 15 | steps: 16 | - name: 'Check out code' 17 | uses: actions/checkout@v4 18 | with: 19 | fetch-depth: 0 20 | token: ${{ secrets.JENKINS_GITHUB_PAT }} 21 | - name: 'Set up Docker' 22 | uses: ./.github/actions/with-docker 23 | with: 24 | container-name: kontrol-ci-integration-${{ github.sha }} 25 | - name: 'Build Kontrol' 26 | run: | 27 | docker exec -u github-user kontrol-ci-integration-${GITHUB_SHA} /bin/bash -c 'CXX=clang++-14 uv run kdist --verbose build -j`nproc` kontrol.*' 28 | - name: 'Run integration tests' 29 | run: | 30 | TEST_ARGS="--maxfail=1000 --numprocesses=2 --update-expected-output --force-sequential -vv" 31 | docker exec --user github-user kontrol-ci-integration-${GITHUB_SHA} bash -c "make cov-integration TEST_ARGS='${TEST_ARGS} -k \"not (test_kontrol_cse or test_foundry_minimize_proof or test_kontrol_end_to_end)\"' || true" 32 | docker exec --user github-user kontrol-ci-integration-${GITHUB_SHA} bash -c "make cov-integration TEST_ARGS='${TEST_ARGS} -k \"test_kontrol_cse or test_foundry_minimize_proof\"' || true" 33 | docker exec --user github-user kontrol-ci-integration-${GITHUB_SHA} bash -c "make cov-integration TEST_ARGS='${TEST_ARGS} -k \"test_kontrol_end_to_end\"' || true" 34 | - name: 'Copy updated files to host' 35 | run: | 36 | docker cp kontrol-ci-integration-${GITHUB_SHA}:/home/github-user/workspace/src/tests/integration/test-data/show ./src/tests/integration/test-data/ 37 | - name: 'Configure GitHub user' 38 | run: | 39 | git config user.name devops 40 | git config user.email devops@runtimeverification.com 41 | - name: 'Push golden files to branch' 42 | run: | 43 | git add ./src/tests/integration/test-data/show 44 | git commit -m "Update expected output files" 45 | git push 46 | - name: 'Tear down Docker' 47 | if: always() 48 | run: | 49 | docker stop --time=0 kontrol-ci-integration-${GITHUB_SHA} 50 | -------------------------------------------------------------------------------- /.github/workflows/update-version.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: 'Update Version' 3 | on: 4 | push: 5 | branches: 6 | - '_update-deps/runtimeverification/evm-semantics' 7 | - '_update-deps-cron/uv2nix' 8 | - '_update-deps-cron/pyproject-build-systems' 9 | workflow_dispatch: 10 | # Stop in progress workflows on the same branch and same workflow to use latest committed code 11 | concurrency: 12 | group: ${{ github.workflow }}-${{ github.ref }} 13 | cancel-in-progress: true 14 | 15 | jobs: 16 | update-versions: 17 | name: 'Update Dependency Versions' 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: 'Check out code' 21 | uses: actions/checkout@v3 22 | with: 23 | submodules: recursive 24 | token: ${{ secrets.JENKINS_GITHUB_PAT }} 25 | fetch-depth: 0 26 | - name: 'Configure GitHub user' 27 | run: | 28 | git config user.name devops 29 | git config user.email devops@runtimeverification.com 30 | - name: 'Install Nix' 31 | uses: cachix/install-nix-action@v31.2.0 32 | with: 33 | install_url: https://releases.nixos.org/nix/nix-2.24.12/install 34 | extra_nix_config: | 35 | substituters = http://cache.nixos.org https://cache.iog.io 36 | trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ= 37 | access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} 38 | - uses: cachix/cachix-action@v16 39 | with: 40 | name: k-framework 41 | authToken: ${{ secrets.CACHIX_PUBLIC_TOKEN }} 42 | # note: we install uv from the nix flake in order to match the uv version that is used by uv2nix 43 | - name: 'Install uv' 44 | run: | 45 | nix profile install .#uv 46 | uv --version 47 | - name: 'Update kevm-pyk release tag' 48 | run: | 49 | KEVM_VERSION="$(cat deps/kevm_release)" 50 | sed -i 's! "kevm-pyk@git+https://github.com/runtimeverification/evm-semantics.git@[v0-9\.]*#subdirectory=kevm-pyk"! "kevm-pyk@git+https://github.com/runtimeverification/evm-semantics.git@v'${KEVM_VERSION}'#subdirectory=kevm-pyk"!' pyproject.toml 51 | uv lock --upgrade 52 | git add -u && git commit -m "Sync uv files: kevm-pyk version ${KEVM_VERSION}" || true 53 | - name: 'Update K release file' 54 | run: | 55 | K_VERSION=$(uv run python3 -c 'import pyk; print(pyk.__version__)') 56 | echo ${K_VERSION} > deps/k_release 57 | git add deps/k_release && git commit -m "deps/k_release: sync release file version ${K_VERSION}" || true 58 | - name: 'Update Nix flake inputs' 59 | run: | 60 | KEVM_VERSION=$(cat deps/kevm_release) 61 | UV2NIX_VERSION=$(cat deps/uv2nix) 62 | PYPROJECT_BUILD_SYSTEMS_VERSION=$(cat deps/pyproject-build-systems) 63 | sed -i 's! kevm.url = "github:runtimeverification/evm-semantics/[v0-9\.]*"! kevm.url = "github:runtimeverification/evm-semantics/v'"${KEVM_VERSION}"'"!' flake.nix 64 | sed -i 's! uv2nix.url = "github:pyproject-nix/uv2nix/[a-z0-9\.]*"! uv2nix.url = "github:pyproject-nix/uv2nix/'"${UV2NIX_VERSION}"'"!' flake.nix 65 | sed -i 's! pyproject-build-systems.url = "github:pyproject-nix/build-system-pkgs/[a-z0-9\.]*"! pyproject-build-systems.url = "github:pyproject-nix/build-system-pkgs/'"${PYPROJECT_BUILD_SYSTEMS_VERSION}"'"!' flake.nix 66 | nix flake update 67 | git add flake.nix flake.lock && git commit -m 'flake.{nix,lock}: update Nix derivations' || true 68 | - name: 'Push updates' 69 | run: git push 70 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /dist/ 3 | __pycache__/ 4 | .coverage 5 | .vscode 6 | src/tests/integration/test-data/foundry/cache 7 | src/tests/integration/test-data/foundry/lib 8 | src/tests/integration/test-data/foundry/out 9 | lib/ -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "docs/state-diff/lib/forge-std"] 2 | path = docs/external-computation/lib/forge-std 3 | url = https://github.com/foundry-rs/forge-std 4 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG Z3_VERSION 2 | ARG K_VERSION 3 | FROM runtimeverificationinc/z3:ubuntu-jammy-${Z3_VERSION} as Z3 4 | 5 | ARG K_VERSION 6 | FROM runtimeverificationinc/kframework-k:ubuntu-jammy-${K_VERSION} 7 | 8 | ARG PYTHON_VERSION=3.10 9 | 10 | # Upgrade z3 to match the version Kontrol was built with not minimum version used in K. 11 | COPY --from=Z3 /usr/bin/z3 /usr/bin/z3 12 | 13 | RUN apt-get -y update \ 14 | && apt-get -y install \ 15 | autoconf \ 16 | cmake \ 17 | curl \ 18 | graphviz \ 19 | libsecp256k1-dev \ 20 | libssl-dev \ 21 | libtool \ 22 | python${PYTHON_VERSION} \ 23 | python${PYTHON_VERSION}-dev \ 24 | && apt-get -y clean 25 | 26 | ARG USER_ID=1010 27 | ARG GROUP_ID=1010 28 | RUN groupadd -g ${GROUP_ID} user \ 29 | && useradd -m -u ${USER_ID} -s /bin/bash -g user user 30 | 31 | USER user 32 | WORKDIR /home/user 33 | 34 | ENV PATH=/home/user/.foundry/bin:${PATH} 35 | RUN curl -L https://foundry.paradigm.xyz | bash \ 36 | && foundryup 37 | 38 | ADD . kontrol 39 | USER root 40 | RUN chown -R user:user kontrol 41 | USER user 42 | 43 | ENV PATH=/home/user/.local/bin:${PATH} 44 | RUN pip install ./kontrol \ 45 | && rm -rf kontrol \ 46 | && CXX=clang++-14 kdist --verbose build -j4 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2023-2024, Runtime Verification Inc. 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | UV := uv 2 | UV_RUN := $(UV) run -- 3 | 4 | 5 | default: check test-unit 6 | 7 | all: check cov 8 | 9 | .PHONY: clean 10 | clean: 11 | rm -rf dist .coverage cov-* .mypy_cache .pytest_cache 12 | find -type d -name __pycache__ -prune -exec rm -rf {} \; 13 | 14 | 15 | # Tests 16 | 17 | TEST_ARGS := 18 | 19 | test: test-all 20 | 21 | .PHONY: test-all 22 | test-all: 23 | $(UV_RUN) pytest src/tests --maxfail=1 --verbose --durations=0 --numprocesses=4 --dist=worksteal $(TEST_ARGS) 24 | 25 | .PHONY: test-unit 26 | test-unit: 27 | $(UV_RUN) pytest src/tests/unit --maxfail=1 --verbose $(TEST_ARGS) 28 | 29 | .PHONY: test-integration 30 | test-integration: 31 | $(UV_RUN) pytest src/tests/integration --maxfail=1 --verbose --durations=0 --numprocesses=4 --dist=worksteal $(TEST_ARGS) 32 | 33 | 34 | # Coverage 35 | 36 | COV_ARGS := 37 | 38 | cov: cov-all 39 | 40 | cov-%: TEST_ARGS += --cov=kontrol --no-cov-on-fail --cov-branch --cov-report=term 41 | 42 | cov-all: TEST_ARGS += --cov-report=html:cov-all-html $(COV_ARGS) 43 | cov-all: test-all 44 | 45 | cov-unit: TEST_ARGS += --cov-report=html:cov-unit-html $(COV_ARGS) 46 | cov-unit: test-unit 47 | 48 | cov-integration: TEST_ARGS += --cov-report=html:cov-integration-html $(COV_ARGS) 49 | cov-integration: test-integration 50 | 51 | 52 | # Profiling 53 | 54 | PROF_ARGS := 55 | 56 | .PHONY: profile 57 | profile: 58 | $(UV_RUN) pytest src/tests/profiling --maxfail=1 --verbose --durations=0 --numprocesses=4 --dist=worksteal $(PROF_ARGS) 59 | find /tmp/pytest-of-$$(whoami)/pytest-current/ -type f -name '*.prof' | sort | xargs tail -n +1 60 | 61 | 62 | # Checks and formatting 63 | 64 | format: autoflake isort black 65 | check: check-flake8 check-mypy check-autoflake check-isort check-black 66 | 67 | .PHONY: check-flake8 68 | check-flake8: 69 | $(UV_RUN) flake8 src 70 | 71 | .PHONY: check-mypy 72 | check-mypy: 73 | $(UV_RUN) mypy src 74 | 75 | .PHONY: autoflake 76 | autoflake: 77 | $(UV_RUN) autoflake --quiet --in-place src 78 | 79 | .PHONY: check-autoflake 80 | check-autoflake: 81 | $(UV_RUN) autoflake --quiet --check src 82 | 83 | .PHONY: isort 84 | isort: 85 | $(UV_RUN) isort src 86 | 87 | .PHONY: check-isort 88 | check-isort: 89 | $(UV_RUN) isort --check src 90 | 91 | .PHONY: black 92 | black: 93 | $(UV_RUN) black src 94 | 95 | .PHONY: check-black 96 | check-black: 97 | $(UV_RUN) black --check src 98 | 99 | 100 | # Optional tools 101 | 102 | SRC_FILES := $(shell find src -type f -name '*.py') 103 | 104 | .PHONY: pyupgrade 105 | pyupgrade: 106 | $(UV_RUN) pyupgrade --py310-plus $(SRC_FILES) 107 | -------------------------------------------------------------------------------- /deps/k_release: -------------------------------------------------------------------------------- 1 | 7.1.253 2 | -------------------------------------------------------------------------------- /deps/kevm_release: -------------------------------------------------------------------------------- 1 | 1.0.841 2 | -------------------------------------------------------------------------------- /deps/pyproject-build-systems: -------------------------------------------------------------------------------- 1 | 7dba6dbc73120e15b558754c26024f6c93015dd7 -------------------------------------------------------------------------------- /deps/uv2nix: -------------------------------------------------------------------------------- 1 | 680e2f8e637bc79b84268949d2f2b2f5e5f1d81c 2 | -------------------------------------------------------------------------------- /deps/z3: -------------------------------------------------------------------------------- 1 | 4.13.4 2 | -------------------------------------------------------------------------------- /docs/external-computation/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiler files 2 | cache/ 3 | out/ 4 | kout-proofs/ 5 | 6 | # State diff files 7 | state-diff/ 8 | 9 | # Ignores development broadcast logs 10 | !/broadcast 11 | /broadcast/*/31337/ 12 | /broadcast/**/dry-run/ 13 | 14 | # Docs 15 | docs/ 16 | 17 | # Dotenv file 18 | .env 19 | -------------------------------------------------------------------------------- /docs/external-computation/foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | src = "src" 3 | out = "out" 4 | libs = ["lib"] 5 | fs_permissions = [ 6 | { access="read-write", path="state-diff" } 7 | ] 8 | 9 | [profile.kprove] 10 | src = "test/kontrol/proofs" 11 | out = "kout-proofs" 12 | test = "test/kontrol/proofs" 13 | script = "test/kontrol/proofs" 14 | 15 | # See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options 16 | -------------------------------------------------------------------------------- /docs/external-computation/script/Counter.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.13; 3 | 4 | import {Script, console} from "forge-std/Script.sol"; 5 | 6 | contract CounterScript is Script { 7 | function setUp() public {} 8 | 9 | function run() public { 10 | vm.broadcast(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /docs/external-computation/src/Counter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.13; 3 | 4 | contract Counter { 5 | uint256 public number; 6 | 7 | function setNumber(uint256 newNumber) public { 8 | number = newNumber; 9 | } 10 | 11 | function increment() public { 12 | number++; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /docs/external-computation/test/Counter.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.13; 3 | 4 | import {Test, console} from "forge-std/Test.sol"; 5 | import {Counter} from "../src/Counter.sol"; 6 | 7 | contract CounterTest is Test { 8 | Counter public counter; 9 | 10 | function setUp() public { 11 | counter = new Counter(); 12 | counter.setNumber(0); 13 | } 14 | 15 | function test_Increment() public { 16 | counter.increment(); 17 | assertEq(counter.number(), 1); 18 | } 19 | 20 | function testFuzz_SetNumber(uint256 x) public { 21 | counter.setNumber(x); 22 | assertEq(counter.number(), x); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /docs/external-computation/test/kontrol/proofs/Counter.k.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.13; 3 | 4 | /* import {Test, console} from "forge-std/Test.sol"; */ 5 | /* import {Counter} from "../src/Counter.sol"; */ 6 | import {Vm} from "forge-std/Vm.sol"; 7 | import {InitialState} from "./utils/InitialState.sol"; 8 | import {ICounter as Counter} from "./utils/Interfaces.sol"; 9 | 10 | contract CounterKontrol is InitialState { 11 | // Cheat code address, 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D 12 | address private constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code")))); 13 | Vm private constant vm = Vm(VM_ADDRESS); 14 | 15 | Counter[] public counters; 16 | 17 | function setUp() public { 18 | counters.push(Counter(address(counter0Address))); 19 | counters.push(Counter(address(counter1Address))); 20 | counters.push(Counter(address(counter2Address))); 21 | counters.push(Counter(address(counter3Address))); 22 | counters.push(Counter(address(counter4Address))); 23 | counters.push(Counter(address(counter5Address))); 24 | counters.push(Counter(address(counter6Address))); 25 | counters.push(Counter(address(counter7Address))); 26 | counters.push(Counter(address(counter8Address))); 27 | counters.push(Counter(address(counter9Address))); 28 | } 29 | 30 | function prove_multiple_counters() public { 31 | for (uint256 i; i <= 9; ++i) { 32 | require(counters[i].number() == i, "Bad number"); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /docs/external-computation/test/kontrol/proofs/utils/Interfaces.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | 3 | pragma solidity ^0.8.13; 4 | 5 | interface ICounter { 6 | function number() external returns (uint256); 7 | 8 | function setNumber(uint256) external; 9 | 10 | function increment(uint256) external; 11 | } 12 | -------------------------------------------------------------------------------- /docs/external-computation/test/kontrol/scripts/json/clean_json.py: -------------------------------------------------------------------------------- 1 | """ 2 | Description: 3 | Unescapes the JSON produced by the recordStateDiff modifier 4 | 5 | Usage: 6 | To unescape a state diff JSON with the recordStateDiff modifier 7 | run: python3 clean_json.py $path_to_state_diff_json 8 | The unescaped JSON will rewrite the input file 9 | 10 | License: 11 | MIT License 12 | """ 13 | 14 | import sys 15 | import json 16 | 17 | def clean_json(input_file): 18 | with open(input_file, 'r') as file: 19 | input_string = file.read() 20 | 21 | result = input_string 22 | 23 | # Remove backslashes 24 | result = result.replace('\\', '') 25 | 26 | # Remove " between ] and , 27 | result = result.replace(']",', '],') 28 | 29 | # Remove " between } and ] 30 | result = result.replace('}"]', '}]') 31 | 32 | # Remove " between [ and { 33 | result = result.replace('["{', '[{') 34 | 35 | # Remove " between } and , 36 | result = result.replace('}",', '},') 37 | 38 | # Remove " between , and { 39 | result = result.replace(',"{', ',{') 40 | 41 | # Remove " before [{ 42 | result = result.replace('"[{', '[{') 43 | 44 | # Remove " after }] 45 | result = result.replace('}]"', '}]') 46 | 47 | with open(input_file, 'w') as file: 48 | file.write(result) 49 | 50 | if __name__ == "__main__": 51 | # Check if a file path is provided as a command line argument 52 | if len(sys.argv) != 2: 53 | print("Usage: clean_json.py ") 54 | sys.exit(1) 55 | 56 | input_file_path = sys.argv[1] 57 | 58 | clean_json(input_file_path) 59 | 60 | print(f"Operation completed. Result saved to {input_file_path}") 61 | -------------------------------------------------------------------------------- /docs/external-computation/test/kontrol/scripts/record-state-diff.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | ########################################################################### 5 | # WARNING: This script is meant to be run from the foundry root directory # 6 | # ./test/kontrol/scripts/record-state-diff.sh to run it # 7 | ########################################################################### 8 | 9 | ########################## 10 | # ENVIRNONMENT VARIABLES # 11 | ########################## 12 | 13 | # JSON-related variables 14 | export STATE_DIFF_DIR=state-diff # Relative to the Foundry root directory 15 | export STATE_DIFF_NAME=StateDiff.json 16 | export ADDR_NAMES=AddressNames.json 17 | CLEAN_JSON_PATH=test/kontrol/scripts/json/clean_json.py 18 | 19 | # Where the contract and function that produces the jsons live 20 | RECORDING_CONTRACT_DIR=test/kontrol/state-diff # Relative to the Foundry root directory 21 | RECORDING_CONTRACT_FILE=proof-initialization.sol # Name of the Solidity file 22 | RECORDING_CONTRACT_NAME=CounterBed # Name of the actual contract 23 | RECORDING_CONTRACT_FUNCTION=counterBedNamed # Name of the function with the recordStateDiff modifier 24 | 25 | RECORDING_CONTRACT_PATH="$RECORDING_CONTRACT_DIR/$RECORDING_CONTRACT_FILE:$RECORDING_CONTRACT_NAME" 26 | 27 | # Kontrol-related variables 28 | GENERATED_CONTRACT_NAME=InitialState 29 | GENERATED_CONTRACT_DIR=test/kontrol/proofs/utils # Relative to the Foundry root directory 30 | GENERATED_CONTRACT_LICENSE=UNLICENSED 31 | 32 | #################### 33 | # RECORD EXECUTION # 34 | #################### 35 | 36 | # Run the function with the recordStateDiff modifier 37 | forge script $RECORDING_CONTRACT_PATH --sig "$RECORDING_CONTRACT_FUNCTION" --ffi -vv 38 | # state diff JSON comes out scaped from the last command 39 | # We execute this script to unscape it so that it can be fed to Kontrol 40 | python3 "$CLEAN_JSON_PATH" "$STATE_DIFF_DIR/$STATE_DIFF_NAME" 41 | 42 | ############################### 43 | # GENERATE SOLIDITY CONTRACTS # 44 | ############################### 45 | 46 | # Give the appropriate files to Kontrol to create the contracts 47 | kontrol load-state "$GENERATED_CONTRACT_NAME" "$STATE_DIFF_DIR/$STATE_DIFF_NAME" \ 48 | --contract-names "$STATE_DIFF_DIR/$ADDR_NAMES" \ 49 | --output-dir "$GENERATED_CONTRACT_DIR" \ 50 | --license "$GENERATED_CONTRACT_LICENSE" \ 51 | --from-state-diff 52 | 53 | # Format the code to ensure compatibility with any CI checks 54 | forge fmt "$GENERATED_CONTRACT_DIR/$GENERATED_CONTRACT_NAME.sol" 55 | forge fmt "$GENERATED_CONTRACT_DIR/${GENERATED_CONTRACT_NAME}Code.sol" 56 | -------------------------------------------------------------------------------- /docs/external-computation/test/kontrol/state-diff/proof-initialization.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.13; 3 | 4 | import {Test} from "forge-std/Test.sol"; 5 | import {Counter} from "src/Counter.sol"; 6 | import {RecordStateDiff} from "./record-state-diff/RecordStateDiff.sol"; 7 | 8 | contract CounterBed is Test, RecordStateDiff { 9 | Counter public counter; 10 | 11 | function counterBed() public recordStateDiff { 12 | for (uint256 i; i <= 9; ++i) { 13 | counter = new Counter(); 14 | counter.setNumber(i); 15 | } 16 | } 17 | 18 | function counterBedNamed() public recordStateDiff { 19 | for (uint256 i; i <= 9; ++i) { 20 | counter = new Counter(); 21 | counter.setNumber(i); 22 | save_address(address(counter), string.concat("counter", vm.toString(i))); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /funding.json: -------------------------------------------------------------------------------- 1 | { 2 | "opRetro": { 3 | "projectId": "0x7348ae42266ff626319e8ea5398343b847603b3cc7101b03d8e4fb2b75ea8db3" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /nix/kontrol-pyk/build-systems-overlay.nix: -------------------------------------------------------------------------------- 1 | final: prev: 2 | let 3 | inherit (final) resolveBuildSystem; 4 | inherit (builtins) mapAttrs; 5 | 6 | # Build system dependencies specified in the shape expected by resolveBuildSystem 7 | # The empty lists below are lists of optional dependencies. 8 | # 9 | # A package `foo` with specification written as: 10 | # `setuptools-scm[toml]` in pyproject.toml would be written as 11 | # `foo.setuptools-scm = [ "toml" ]` in Nix 12 | buildSystemOverrides = { 13 | pyperclip.setuptools = [ ]; 14 | kevm-pyk.poetry-core = [ ]; 15 | }; 16 | in 17 | mapAttrs ( 18 | name: spec: 19 | prev.${name}.overrideAttrs (old: { 20 | nativeBuildInputs = old.nativeBuildInputs ++ resolveBuildSystem spec; 21 | }) 22 | ) buildSystemOverrides -------------------------------------------------------------------------------- /nix/kontrol-pyk/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | callPackage, 4 | stdenvNoCC, 5 | 6 | pyproject-nix, 7 | pyproject-build-systems, 8 | uv2nix, 9 | 10 | python, 11 | solc_version ? null 12 | }: 13 | let 14 | pyproject-util = callPackage pyproject-nix.build.util {}; 15 | pyproject-packages = callPackage pyproject-nix.build.packages { 16 | inherit python; 17 | }; 18 | 19 | # patches cannot yet be applied to uv workspaces, so we use a derivation containing the src instead 20 | src = stdenvNoCC.mkDerivation { 21 | name = "kontrol-pyk-src"; 22 | src = callPackage ../kontrol-source { }; 23 | 24 | dontConfigure = true; 25 | dontBuild = true; 26 | 27 | postPatch = '' 28 | ${lib.strings.optionalString (solc_version != null) '' 29 | substituteInPlace ./src/kontrol/foundry.py \ 30 | --replace "'forge', 'build'," "'forge', 'build', '--no-auto-detect'," 31 | ''} 32 | ''; 33 | 34 | installPhase = '' 35 | mkdir -p $out 36 | cp -r . $out/ 37 | ''; 38 | }; 39 | 40 | # load a uv workspace from a workspace root 41 | workspace = uv2nix.lib.workspace.loadWorkspace { 42 | workspaceRoot = "${src}"; 43 | }; 44 | 45 | # create overlay 46 | lockFileOverlay = workspace.mkPyprojectOverlay { 47 | # prefer "wheel" over "sdist" due to maintance overhead 48 | # there is no bundled set of overlays for "sdist" in uv2nix, in contrast to poetry2nix 49 | sourcePreference = "wheel"; 50 | }; 51 | 52 | buildSystemsOverlay = import ./build-systems-overlay.nix; 53 | 54 | # construct package set 55 | pythonSet = pyproject-packages.overrideScope (lib.composeManyExtensions [ 56 | # make build tools available by default as these are not necessarily specified in python lock files 57 | pyproject-build-systems.overlays.default 58 | # include all packages from the python lock file 59 | lockFileOverlay 60 | # add build system overrides to certain python packages 61 | buildSystemsOverlay 62 | ]); 63 | in pyproject-util.mkApplication { 64 | # default dependancy group enables no optional dependencies and no dependency-groups 65 | venv = pythonSet.mkVirtualEnv "kontrol-pyk-env" workspace.deps.default; 66 | package = pythonSet.kontrol; 67 | } 68 | -------------------------------------------------------------------------------- /nix/kontrol-source/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | nix-gitignore 4 | }: 5 | 6 | lib.cleanSource (nix-gitignore.gitignoreSourcePure [ 7 | ../../.gitignore 8 | ".github/" 9 | "result*" 10 | "/deps/" 11 | # do not include submodule directories that might be initilized empty or non-existent 12 | "/docs/external-computation" 13 | ] ../../. 14 | ) -------------------------------------------------------------------------------- /nix/kontrol/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | stdenv, 4 | runCommand, 5 | makeWrapper, 6 | callPackage, 7 | 8 | autoconf, 9 | automake, 10 | cmake, 11 | git, 12 | clang, 13 | k, 14 | boost, 15 | libtool, 16 | mpfr, 17 | openssl, 18 | gmp, 19 | pkg-config, 20 | secp256k1, 21 | kevm, 22 | which, 23 | foundry-bin, 24 | solcMkDefault, 25 | solc_0_8_13, 26 | solc_0_8_15, 27 | solc_0_8_22, 28 | 29 | kontrol-pyk, 30 | solc_version ? null, 31 | rev ? null 32 | } @ args: 33 | let 34 | kontrol-pyk-solc = kontrol-pyk.override { inherit solc_version; }; 35 | nixLibs = "-I${openssl.dev}/include -L${openssl.out}/lib -I${secp256k1}/include -L${secp256k1}/lib"; 36 | in 37 | stdenv.mkDerivation { 38 | pname = "kontrol"; 39 | version = if (rev != null) then rev else "dirty"; 40 | buildInputs = [ 41 | autoconf 42 | automake 43 | cmake 44 | git 45 | clang 46 | kontrol-pyk-solc 47 | k 48 | boost 49 | libtool 50 | mpfr 51 | openssl.dev 52 | gmp 53 | pkg-config 54 | secp256k1 55 | ]; 56 | nativeBuildInputs = [ makeWrapper ]; 57 | 58 | src = callPackage ../kontrol-source { }; 59 | 60 | dontUseCmakeConfigure = true; 61 | 62 | enableParallelBuilding = true; 63 | 64 | buildPhase = '' 65 | XDG_CACHE_HOME=$(pwd) NIX_LIBS="${nixLibs}" ${ 66 | lib.optionalString 67 | (stdenv.isAarch64 && stdenv.isDarwin) 68 | "APPLE_SILICON=true" 69 | } kontrol-kdist -v build kontrol.base 70 | ''; 71 | 72 | installPhase = '' 73 | mkdir -p $out 74 | cp -r ./kdist-*/* $out/ 75 | ln -s ${kevm}/evm-semantics $out/evm-semantics 76 | mkdir -p $out/bin 77 | ln -s ${kevm}/bin/kevm $out/bin/kevm 78 | makeWrapper ${kontrol-pyk-solc}/bin/kontrol $out/bin/kontrol --prefix PATH : ${ 79 | lib.makeBinPath 80 | ([ which k ] ++ lib.optionals (solc_version != null) [ 81 | foundry-bin 82 | (solcMkDefault { inherit runCommand lib; } solc_version) 83 | ]) 84 | } --set NIX_LIBS "${nixLibs}" --set KDIST_DIR $out 85 | ''; 86 | 87 | passthru = if solc_version == null then { 88 | # list all supported solc versions here 89 | solc_0_8_13 = callPackage ./default.nix (args // { solc_version = solc_0_8_13; }); 90 | solc_0_8_15 = callPackage ./default.nix (args // { solc_version = solc_0_8_15; }); 91 | solc_0_8_22 = callPackage ./default.nix (args // { solc_version = solc_0_8_22; }); 92 | } else { }; 93 | } -------------------------------------------------------------------------------- /package/test-package.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euxo pipefail 4 | 5 | which kontrol 6 | kontrol --help 7 | kontrol version 8 | 9 | cd test-project 10 | kontrol build 11 | kontrol prove --match-test 'AssertTest.test_assert_true()' 12 | -------------------------------------------------------------------------------- /package/test-project/foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | src = 'src' 3 | out = 'out' 4 | extra_output = ['storageLayout', 'abi', 'evm.methodIdentifiers', 'evm.deployedBytecode.object', 'devdoc'] 5 | -------------------------------------------------------------------------------- /package/test-project/test/Simple.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | contract AssertTest { 5 | function test_assert_true() public pure { 6 | assert(true); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /package/version: -------------------------------------------------------------------------------- 1 | 1.0.0 2 | -------------------------------------------------------------------------------- /package/version.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -xeuo pipefail 4 | 5 | notif() { echo "== $@" >&2 ; } 6 | fatal() { echo "[FATAL] $@" ; exit 1 ; } 7 | 8 | version_file="package/version" 9 | 10 | version_bump() { 11 | local version release_commit version_major version_minor version_patch new_version current_version current_version_major current_version_minor current_version_patch 12 | version="$(cat ${version_file})" 13 | version_major="$(echo ${version} | cut --delimiter '.' --field 1)" 14 | version_minor="$(echo ${version} | cut --delimiter '.' --field 2)" 15 | version_patch="$(echo ${version} | cut --delimiter '.' --field 3)" 16 | current_version="$(cat ${version_file})" 17 | current_version_major="$(echo ${current_version} | cut --delimiter '.' --field 1)" 18 | current_version_minor="$(echo ${current_version} | cut --delimiter '.' --field 2)" 19 | current_version_patch="$(echo ${current_version} | cut --delimiter '.' --field 3)" 20 | new_version="${version}" 21 | if [[ "${version_major}" == "${current_version_major}" ]] && [[ "${version_minor}" == "${current_version_minor}" ]]; then 22 | new_version="${version_major}.${version_minor}.$((version_patch + 1))" 23 | fi 24 | echo "${new_version}" > "${version_file}" 25 | notif "Version: ${new_version}" 26 | } 27 | 28 | version_sub() { 29 | local version 30 | version="$(cat $version_file)" 31 | sed --in-place 's/^version = ".*"$/version = "'${version}'"/' pyproject.toml 32 | sed --in-place "s/^VERSION: Final = '.*'$/VERSION: Final = '${version}'/" src/kontrol/__init__.py 33 | } 34 | 35 | version_command="$1" ; shift 36 | 37 | case "${version_command}" in 38 | bump) version_bump "$@" ;; 39 | sub) version_sub "$@" ;; 40 | *) fatal "No command: ${version_command}" ;; 41 | esac 42 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["hatchling"] 3 | build-backend = "hatchling.build" 4 | 5 | [project] 6 | name = "kontrol" 7 | version = "1.0.0" 8 | description = "Foundry integration for KEVM" 9 | requires-python = "~=3.10" 10 | dependencies = [ 11 | "kevm-pyk@git+https://github.com/runtimeverification/evm-semantics.git@v1.0.841#subdirectory=kevm-pyk", 12 | "eth-utils>=4.1.1,<5", 13 | "pycryptodome>=3.20.0,<4", 14 | "pyevmasm>=0.2.3,<0.3", 15 | ] 16 | 17 | [[project.authors]] 18 | name = "Runtime Verification, Inc." 19 | email = "contact@runtimeverification.com" 20 | 21 | [project.scripts] 22 | kontrol = "kontrol.__main__:main" 23 | kontrol-kdist = "pyk.kdist.__main__:main" 24 | 25 | [project.entry-points.kdist] 26 | kontrol = "kontrol.kdist.plugin" 27 | 28 | [dependency-groups] 29 | dev = [ 30 | "autoflake", 31 | "black", 32 | "flake8", 33 | "flake8-bugbear", 34 | "flake8-comprehensions", 35 | "flake8-quotes", 36 | "flake8-type-checking", 37 | "isort", 38 | "mypy", 39 | "pep8-naming", 40 | "pytest>=7,<8", 41 | "pytest-cov", 42 | "pytest-mock", 43 | "pytest-xdist", 44 | "pytest-timeout", 45 | "pyupgrade", 46 | ] 47 | 48 | [tool.hatch.metadata] 49 | allow-direct-references = true 50 | 51 | [tool.isort] 52 | profile = "black" 53 | line_length = 120 54 | 55 | [tool.autoflake] 56 | recursive = true 57 | expand-star-imports = true 58 | remove-all-unused-imports = true 59 | ignore-init-module-imports = true 60 | remove-duplicate-keys = true 61 | remove-unused-variables = true 62 | exclude = "src/tests/integration/test-data" 63 | 64 | [tool.black] 65 | line-length = 120 66 | skip-string-normalization = true 67 | 68 | [tool.mypy] 69 | disallow_untyped_defs = true 70 | exclude = "src/tests/integration/test-data" 71 | -------------------------------------------------------------------------------- /src/kontrol/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | if TYPE_CHECKING: 6 | from typing import Final 7 | 8 | VERSION: Final = '1.0.0' 9 | -------------------------------------------------------------------------------- /src/kontrol/kdist/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runtimeverification/kontrol/28d44863fbae232e3ab1e6677fda3af843917150/src/kontrol/kdist/__init__.py -------------------------------------------------------------------------------- /src/kontrol/kdist/hevm.md: -------------------------------------------------------------------------------- 1 | ### hevm Success Predicate 2 | 3 | The [hevm](https://github.com/ethereum/hevm) success predicate option was implemented for [benchmarking](https://github.com/eth-sc-comp/benchmarks/tree/deb3faa7e42993a057ba52935368a89f08970f19) purposes. 4 | 5 | `hevm symbolic` searches for assertions violations, where an assertion violation is defined as either an execution of the invalid opcode (`0xfe`), or a revert with a message of the form `abi.encodeWithSelector('Panic(uint256)', errCode)` with `errCode` being one of the predefined Solidity assertion codes defined [here](https://docs.soliditylang.org/en/latest/control-structures.html#panic-via-assert-and-error-via-require) (by default, `hevm` ignores assertion violations that result from arithmetic overflow (`Panic(0x11)`). 6 | 7 | Notice that `hevm symbolic` does not fail with `revert` statements, nor with `require` clauses. Instead `require` clauses are used to impose assumptions, being the equivalent to `vm.assume`. 8 | 9 | Although `hevm symbolic` does not fail on `DSTest` assertions, for compatibility with `hevm test` and `Halmos`, we decided to check only user-defined solidity assertion violations and `DSTest` violations, in addition to the invalid opcode. 10 | 11 | ```k 12 | module HEVM-SUCCESS 13 | imports EVM 14 | imports EVM-ABI 15 | 16 | syntax Bool ::= 17 | "hevm_success" "(" 18 | statusCode: StatusCode "," 19 | failed: Int "," 20 | output: Bytes 21 | ")" [function, symbol(hevm_success)] 22 | // -------------------------------------- 23 | rule hevm_success(EVMC_SUCCESS, 0, _) => true 24 | rule hevm_success(EVMC_REVERT, _, OUT) => true 25 | requires notBool( #range(OUT, 0, 4) ==K Int2Bytes(4, selector ("Panic(uint256)"), BE) 26 | andBool #range(OUT, 35, 1) ==K b"\x01" ) //Error code for user defined assertions 27 | rule hevm_success(_, _, _) => false [owise] 28 | 29 | rule ( selector ( "Panic(uint256)" ) => 1313373041 ) 30 | ``` 31 | 32 | ### hevm Fail Predicate 33 | 34 | In order to support `proveFail` we also defined the hevm fail predicate. This predicate asserts that all branches are failing, i.e. there is not a branch ending with `EVMC_SUCCESS` and not violating a `DS-TEST` assertion. 35 | 36 | `proveFail` is not supported by `hevm symbolic`, however it is supported by `hevm test`. Therefore, this predicate is defined to be compatible with `hevm test`, meaning that it checks whether all branches revert. 37 | 38 | ```k 39 | syntax Bool ::= 40 | "hevm_fail" "(" 41 | statusCode: StatusCode "," 42 | failed: Int 43 | ")" [function, symbol(hevm_fail)] 44 | // ----------------------------------- 45 | rule hevm_fail(EVMC_SUCCESS, 0) => false 46 | rule hevm_fail(_, _) => true [owise] 47 | 48 | endmodule 49 | ``` 50 | -------------------------------------------------------------------------------- /src/kontrol/kdist/keccak.md: -------------------------------------------------------------------------------- 1 | Keccak Assumptions 2 | ============== 3 | 4 | The provided K Lemmas define assumptions and properties related to the `keccak` hash function used in the verification of smart contracts within the symbolic execution context. 5 | 6 | ```k 7 | module KECCAK-LEMMAS 8 | imports FOUNDRY 9 | imports INT-SYMBOLIC 10 | ``` 11 | 12 | 1. `keccak` always returns an integer in the range `[0, 2 ^ 256)`. 13 | 14 | ```k 15 | rule 0 <=Int keccak( _ ) => true [simplification, smt-lemma] 16 | rule keccak( _ ) true [simplification, smt-lemma] 17 | ``` 18 | 19 | 2. No value outside of the `[0, 2 ^ 256)` range can be the result of a `keccak`. 20 | 21 | ```k 22 | rule [keccak-out-of-range]: X ==Int keccak (_) => false requires X =Int pow256 [concrete(X), simplification] 23 | rule [keccak-out-of-range-ml]: { X #Equals keccak (_) } => #Bottom requires X =Int pow256 [concrete(X), simplification] 24 | ``` 25 | 26 | 3. This lemma directly simplifies an expression that involves a `keccak` and is often introduced by the Solidity compiler. 27 | 28 | ```k 29 | rule chop (0 -Int keccak(BA)) => pow256 -Int keccak(BA) 30 | [simplification] 31 | ``` 32 | 33 | 4. The result of a `keccak` is assumed not to fall too close to the edges of its official range. This accounts for the shifts added to the result of a `keccak` when accessing storage slots, and is a hypothesis made by the ecosystem. 34 | 35 | ```k 36 | rule BOUND:Int true requires BOUND <=Int 32 [simplification, concrete(BOUND)] 37 | rule keccak(_B:Bytes) true requires BOUND >=Int pow256 -Int 32 [simplification, concrete(BOUND)] 38 | ``` 39 | 40 | 5. `keccak` is injective: that is, if `keccak(A)` equals `keccak(B)`, then `A` equals `B`. 41 | 42 | In reality, cryptographic hash functions like `keccak` are not injective. They are designed to be collision-resistant, meaning it is computationally infeasible to find two different inputs that produce the same hash output, but not impossible. 43 | This assumption reflects that hypothesis in the context of formal verification, making it more tractable. 44 | 45 | ```k 46 | rule [keccak-inj]: keccak(A) ==Int keccak(B) => A ==K B [simplification] 47 | rule [keccak-inj-ml]: { keccak(A) #Equals keccak(B) } => { true #Equals A ==K B } [simplification] 48 | ``` 49 | 50 | 6. `keccak` of a symbolic parameter does not equal a concrete value. This lemma is based on our experience in Foundry-supported testing and is specific to how `keccak` functions are used in practical symbolic execution. The underlying hypothesis that justifies it is that the storage slots of a given mapping are presumed to be disjoint from slots of other mappings and also the non-mapping slots of a contract. 51 | 52 | ```k 53 | rule [keccak-eq-conc-false]: keccak(_A) ==Int _B => false [symbolic(_A), concrete(_B), simplification(30), comm] 54 | rule [keccak-neq-conc-true]: keccak(_A) =/=Int _B => true [symbolic(_A), concrete(_B), simplification(30), comm] 55 | 56 | rule [keccak-eq-conc-false-ml-lr]: { keccak(A) #Equals B } => { true #Equals keccak(A) ==Int B } [symbolic(A), concrete(B), simplification] 57 | rule [keccak-eq-conc-false-ml-rl]: { B #Equals keccak(A) } => { true #Equals keccak(A) ==Int B } [symbolic(A), concrete(B), simplification] 58 | ``` 59 | 60 | ```k 61 | endmodule 62 | ``` -------------------------------------------------------------------------------- /src/kontrol/kdist/kontrol.md: -------------------------------------------------------------------------------- 1 | Kontrol Definitions 2 | =================== 3 | 4 | This file defines the pre-built Kontrol definitions you get with a fresh install of Kontrol. 5 | They include the base Foundry definition, and some optional lemmas (using command-line arguments to specify which ones to include). 6 | 7 | ```k 8 | requires "foundry.md" 9 | requires "no_stack_checks.md" 10 | requires "no_code_size_checks.md" 11 | requires "keccak.md" 12 | requires "kontrol_lemmas.md" 13 | 14 | module KONTROL-BASE 15 | imports FOUNDRY 16 | imports NO-STACK-CHECKS 17 | imports NO-CODE-SIZE-CHECKS 18 | endmodule 19 | 20 | module KONTROL-AUX 21 | imports KONTROL-BASE 22 | imports KONTROL-AUX-LEMMAS 23 | endmodule 24 | 25 | module KONTROL-KECCAK 26 | imports KONTROL-BASE 27 | imports KECCAK-LEMMAS 28 | endmodule 29 | 30 | module KONTROL-FULL 31 | imports KONTROL-AUX 32 | imports KONTROL-KECCAK 33 | endmodule 34 | ``` 35 | -------------------------------------------------------------------------------- /src/kontrol/kdist/no_code_size_checks.md: -------------------------------------------------------------------------------- 1 | Relaxed Bytecode Limits Rules 2 | =================== 3 | 4 | The provided rule disables the enforcement of the code size limit introduced in EIP-170 during contract deployment. 5 | That enables the deployment of larger test contracts containing auxiliary functions for verification and testing. 6 | In addition, it enhances compatibility with Foundry, which also does not enforce the code size limit. 7 | 8 | ```k 9 | requires "foundry.md" 10 | 11 | module NO-CODE-SIZE-CHECKS 12 | imports EVM 13 | imports FOUNDRY 14 | 15 | rule [deploy-no-codesize-limit]: 16 | #mkCodeDeposit ACCT 17 | => Gcodedeposit < SCHED > *Int lengthBytes(OUT) ~> #deductGas 18 | ~> #finishCodeDeposit ACCT OUT 19 | ... 20 | 21 | SCHED 22 | OUT => .Bytes 23 | requires #isValidCode(OUT, SCHED) 24 | [priority(30)] 25 | 26 | rule [create-valid-no-codesize-limit]: 27 | CREATE VALUE MEMSTART MEMWIDTH 28 | => #accessAccounts #newAddr(ACCT, NONCE) 29 | ~> #checkCreate ACCT VALUE 30 | ~> #create ACCT #newAddr(ACCT, NONCE) VALUE #range(LM, MEMSTART, MEMWIDTH) 31 | ~> #codeDeposit #newAddr(ACCT, NONCE) 32 | ... 33 | 34 | ACCT 35 | LM 36 | 37 | ACCT 38 | NONCE 39 | ... 40 | 41 | [preserves-definedness, priority(30)] 42 | 43 | endmodule 44 | ``` 45 | -------------------------------------------------------------------------------- /src/kontrol/kdist/plugin.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | from kevm_pyk.kdist.plugin import KEVMTarget 6 | from kevm_pyk.kompile import KompileTarget 7 | 8 | from .utils import KSRC_DIR 9 | 10 | if TYPE_CHECKING: 11 | from typing import Final 12 | 13 | 14 | __TARGETS__: Final = { 15 | 'base': KEVMTarget( 16 | { 17 | 'target': KompileTarget.HASKELL, 18 | 'main_file': KSRC_DIR / 'kontrol.md', 19 | 'main_module': 'KONTROL-BASE', 20 | 'syntax_module': 'KONTROL-BASE', 21 | }, 22 | ), 23 | 'keccak': KEVMTarget( 24 | { 25 | 'target': KompileTarget.HASKELL, 26 | 'main_file': KSRC_DIR / 'kontrol.md', 27 | 'main_module': 'KONTROL-KECCAK', 28 | 'syntax_module': 'KONTROL-KECCAK', 29 | }, 30 | ), 31 | 'aux': KEVMTarget( 32 | { 33 | 'target': KompileTarget.HASKELL, 34 | 'main_file': KSRC_DIR / 'kontrol.md', 35 | 'main_module': 'KONTROL-AUX', 36 | 'syntax_module': 'KONTROL-AUX', 37 | }, 38 | ), 39 | 'full': KEVMTarget( 40 | { 41 | 'target': KompileTarget.HASKELL, 42 | 'main_file': KSRC_DIR / 'kontrol.md', 43 | 'main_module': 'KONTROL-FULL', 44 | 'syntax_module': 'KONTROL-FULL', 45 | }, 46 | ), 47 | } 48 | -------------------------------------------------------------------------------- /src/kontrol/kdist/trace.md: -------------------------------------------------------------------------------- 1 | Debug Collection with KEVM 2 | -------------------------- 3 | This module handles the tracing of EVM opcodes during an execution. 4 | 5 | ```k 6 | module EVM-TRACING 7 | imports EVM 8 | ``` 9 | The configuration of the KEVMTracing is defined as following: 10 | - `` signals if the tracing feature is active or not. 11 | - `` signals if the storage should be recorded in the `TraceItem`. 12 | - `` signals if the storage should be recorded in the `TraceItem`. 13 | - `` signals if the storage should be recorded in the `TraceItem`. 14 | - `` is an auxiliary cell that is used to determine if the current step has been recorded or not. 15 | - `` is a collection of `TraceItems`. 16 | 17 | ```k 18 | configuration 19 | 20 | false 21 | false 22 | false 23 | false 24 | false 25 | .List 26 | 27 | ``` 28 | The `TraceItem` is a sort used to save information about the executed opcodes. 29 | Each `TraceItem` contains: 30 | - the current program counter 31 | - the current opcode 32 | - the storage of the contract that is being executed. 33 | - the current word stack 34 | - the current memory 35 | - the current call depth 36 | 37 | ```k 38 | syntax TraceItem ::= "{" Int "|" OpCode "|" WordStack "|" Bytes "|" Map "|" Int "}" 39 | // ----------------------------------------------------------------------------------- 40 | 41 | rule #next [ OPC ] ... 42 | true 43 | DSTG 44 | DSTK 45 | DMEM 46 | false => true 47 | PCOUNT 48 | WS 49 | CD 50 | MEM 51 | ACCT 52 | 53 | ACCT 54 | STORAGE 55 | ... 56 | 57 | 58 | ... 59 | .List => ListItem({ PCOUNT 60 | | OPC 61 | | #if DSTK ==K true #then WS #else .WordStack #fi 62 | | #if DMEM ==K true #then MEM #else .Bytes #fi 63 | | #if DSTG ==K true #then STORAGE #else .Map #fi 64 | | CD 65 | }) 66 | 67 | [priority(25)] 68 | 69 | rule #execute ... 70 | true => false 71 | [priority(25)] 72 | 73 | endmodule 74 | ``` -------------------------------------------------------------------------------- /src/kontrol/kdist/utils.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from pathlib import Path 4 | from typing import TYPE_CHECKING 5 | 6 | if TYPE_CHECKING: 7 | from typing import Final 8 | 9 | 10 | KSRC_DIR: Final = Path(__file__).parent.resolve(strict=True) 11 | -------------------------------------------------------------------------------- /src/kontrol/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runtimeverification/kontrol/28d44863fbae232e3ab1e6677fda3af843917150/src/kontrol/py.typed -------------------------------------------------------------------------------- /src/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runtimeverification/kontrol/28d44863fbae232e3ab1e6677fda3af843917150/src/tests/__init__.py -------------------------------------------------------------------------------- /src/tests/conftest.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | import pytest 6 | from pyk.cli.utils import dir_path 7 | 8 | if TYPE_CHECKING: 9 | from pathlib import Path 10 | 11 | from pytest import FixtureRequest, Parser 12 | 13 | 14 | def pytest_addoption(parser: Parser) -> None: 15 | parser.addoption( 16 | '--foundry-root', 17 | type=dir_path, 18 | help='Use pre-kompiled project directory for proof tests', 19 | ) 20 | parser.addoption( 21 | '--update-expected-output', 22 | action='store_true', 23 | default=False, 24 | help='Write expected output files for proof tests', 25 | ) 26 | parser.addoption( 27 | '--no-use-booster', 28 | action='store_true', 29 | default=False, 30 | help='Use the kore-rpc binary instead of kore-rpc-booster', 31 | ) 32 | parser.addoption( 33 | '--force-sequential', 34 | default=False, 35 | action='store_true', 36 | help='Use sequential, single-threaded proof loop.', 37 | ) 38 | 39 | 40 | @pytest.fixture(scope='session') 41 | def foundry_root_dir(request: FixtureRequest) -> Path | None: 42 | return request.config.getoption('--foundry-root') 43 | 44 | 45 | @pytest.fixture 46 | def update_expected_output(request: FixtureRequest) -> bool: 47 | return request.config.getoption('--update-expected-output') 48 | 49 | 50 | @pytest.fixture(scope='session') 51 | def no_use_booster(request: FixtureRequest) -> bool: 52 | return request.config.getoption('--no-use-booster') 53 | 54 | 55 | @pytest.fixture(scope='session') 56 | def force_sequential(request: FixtureRequest) -> bool: 57 | return request.config.getoption('--force-sequential') 58 | -------------------------------------------------------------------------------- /src/tests/integration/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runtimeverification/kontrol/28d44863fbae232e3ab1e6677fda3af843917150/src/tests/integration/__init__.py -------------------------------------------------------------------------------- /src/tests/integration/test-data/accesses.json: -------------------------------------------------------------------------------- 1 | { 2 | "accountAccesses": [{"accessor":"0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496","account":"0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f","chainInfo":{"chainId":31337,"forkId":0},"data":"0x608060405234801561001057600080fd5b50610106806100206000396000f3fe6080604052348015600f57600080fd5b5060043610603c5760003560e01c80633fb5c1cb1460415780638381f58a146053578063d09de08a14606d575b600080fd5b6051604c3660046083565b600055565b005b605b60005481565b60405190815260200160405180910390f35b6051600080549080607c83609b565b9190505550565b600060208284031215609457600080fd5b5035919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820360f2577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b506001019056fea164736f6c634300080f000a","deployedCode":"0x6080604052348015600f57600080fd5b5060043610603c5760003560e01c80633fb5c1cb1460415780638381f58a146053578063d09de08a14606d575b600080fd5b6051604c3660046083565b600055565b005b605b60005481565b60405190815260200160405180910390f35b6051600080549080607c83609b565b9190505550565b600060208284031215609457600080fd5b5035919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820360f2577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b506001019056fea164736f6c634300080f000a","initialized":true,"kind":"Create","newBalance":0,"oldBalance":0,"reverted":false,"storageAccesses":[],"value":0},{"accessor":"0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496","account":"0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f","chainInfo":{"chainId":31337,"forkId":0},"data":"0x3fb5c1cb0000000000000000000000000000000000000000000000000000000000000003","deployedCode":"0x","initialized":true,"kind":"Call","newBalance":0,"oldBalance":0,"reverted":false,"storageAccesses": [{"account":"0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f","isWrite":true,"newValue":"0x0000000000000000000000000000000000000000000000000000000000000003","previousValue":"0x0000000000000000000000000000000000000000000000000000000000000000","reverted":false,"slot":"0x0000000000000000000000000000000000000000000000000000000000000000"}],"value":0}] 3 | } 4 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/cse-lemmas.k: -------------------------------------------------------------------------------- 1 | requires "evm.md" 2 | requires "foundry.md" 3 | 4 | module CSE-LEMMAS 5 | imports BOOL 6 | imports FOUNDRY 7 | imports INFINITE-GAS 8 | imports INT-SYMBOLIC 9 | imports MAP-SYMBOLIC 10 | imports SET-SYMBOLIC 11 | 12 | // xor in terms of -Int 13 | rule X xorInt maxUInt256 => maxUInt256 -Int X 14 | requires #rangeUInt ( 256 , X ) 15 | [simplification] 16 | 17 | // Set equality needed for discharging `#Not ( #Exists ( ... )` on `` unification 18 | rule { S1:Set #Equals S2:Set |Set SetItem ( X ) } => 19 | { X in S1 } #And 20 | ( { S2 #Equals S1 } #Or { S2 #Equals S1 -Set SetItem ( X ) } ) 21 | [simplification] 22 | 23 | // Non-equality of byte arrays 24 | rule { B1:Bytes #Equals B2:Bytes } => #Bottom 25 | requires notBool ( lengthBytes(B1) ==Int lengthBytes(B2) ) 26 | [simplification] 27 | 28 | // Function selector does not match 29 | rule { B:Bytes #Equals B1:Bytes +Bytes _:Bytes } => #Bottom 30 | requires #range(B, 0, 4) =/=K #range (B1, 0, 4) 31 | [simplification(60), concrete(B, B1)] 32 | 33 | // Function selector matches 34 | rule { B:Bytes #Equals B1:Bytes +Bytes B2:Bytes } => {#range(B, 4, lengthBytes(B) -Int 4) #Equals B2} 35 | requires 4 <=Int lengthBytes(B) andBool #range(B, 0, 4) ==K B1 36 | [simplification(60), concrete(B, B1)] 37 | 38 | // Bitwise inequalities 39 | rule [bitwise-and-maxUInt-lt-l]: 40 | A false 41 | requires 0 <=Int X andBool 0 <=Int Y 42 | andBool X +Int 1 ==Int 2 ^Int log2Int(X +Int 1) 43 | andBool X +Int 1 <=Int A 44 | [concrete(X), simplification, preserves-definedness] 45 | 46 | rule [bitwise-and-maxUInt-le-r]: 47 | X &Int Y <=Int A => true 48 | requires 0 <=Int X andBool 0 <=Int Y 49 | andBool X +Int 1 ==Int 2 ^Int log2Int(X +Int 1) 50 | andBool X +Int 1 <=Int A 51 | [concrete(X), simplification, preserves-definedness] 52 | 53 | rule [powByteLen-compute]: 54 | #powByteLen(SIZE) => 2 ^Int (8 *Int SIZE) 55 | [simplification, concrete(SIZE)] 56 | 57 | endmodule 58 | 59 | module CSE-LEMMAS-SPEC 60 | imports CSE-LEMMAS 61 | 62 | endmodule 63 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/dumpState.json: -------------------------------------------------------------------------------- 1 | {"0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f":{"nonce":"0x1","balance":"0xde0b6b3a7640000","code":"0x6080604052348015600f57600080fd5b5060043610603c5760003560e01c80633fb5c1cb1460415780638381f58a146053578063d09de08a14606d575b600080fd5b6051604c3660046083565b600055565b005b605b60005481565b60405190815260200160405180910390f35b6051600080549080607c83609b565b9190505550565b600060208284031215609457600080fd5b5035919050565b60006001820160ba57634e487b7160e01b600052601160045260246000fd5b506001019056fea2646970667358221220c8a96684004f604cf8378bb0bdec95bf1529b5dac4599543eb798b5e5f9a966f64736f6c634300080d0033","storage":{"0x0000000000000000000000000000000000000000000000000000000000000000":"0x0000000000000000000000000000000000000000000000000000000000000001"}},"0x2e234dae75c793f67a35089c9d99245e1c58470b":{"nonce":"0x1","balance":"0x1bc16d674ec80000","code":"0x6080604052348015600f57600080fd5b5060043610603c5760003560e01c80633fb5c1cb1460415780638381f58a146053578063d09de08a14606d575b600080fd5b6051604c3660046083565b600055565b005b605b60005481565b60405190815260200160405180910390f35b6051600080549080607c83609b565b9190505550565b600060208284031215609457600080fd5b5035919050565b60006001820160ba57634e487b7160e01b600052601160045260246000fd5b506001019056fea2646970667358221220c8a96684004f604cf8378bb0bdec95bf1529b5dac4599543eb798b5e5f9a966f64736f6c634300080d0033","storage":{"0x0000000000000000000000000000000000000000000000000000000000000000":"0x0000000000000000000000000000000000000000000000000000000000000002"}}} -------------------------------------------------------------------------------- /src/tests/integration/test-data/end-to-end-prove-all: -------------------------------------------------------------------------------- 1 | AllowChangesTest.testAllowCalls(uint256) 2 | AllowChangesTest.testFailAllowCalls_ifNotWhitelisted(uint256) 3 | CounterTest.test_Increment() 4 | ForgetBranchTest.test_forgetBranch(uint256) 5 | RandomVarTest.test_custom_names() 6 | RandomVarTest.test_randomAddress() 7 | RandomVarTest.test_randomBool() 8 | RandomVarTest.test_randomBytes_length(uint256) 9 | RandomVarTest.test_randomBytes4_length() 10 | RandomVarTest.test_randomBytes8_length() 11 | RandomVarTest.test_randomUint_192() 12 | RandomVarTest.test_randomUint_Range(uint256,uint256) 13 | RandomVarTest.test_randomUint() 14 | TransientStorageTest.testTransientStoreLoad(uint256,uint256) 15 | UnitTest.test_assert_eq_address_darray(address[]) 16 | UnitTest.test_assert_eq_bool_darray(bool[]) 17 | UnitTest.test_assert_eq_bytes32_darray(bytes32[]) 18 | UnitTest.test_assert_eq_int256_darray(int256[]) 19 | UnitTest.test_assert_eq_uint256_darray(uint256[]) 20 | UnitTest.test_assertApproxEqAbs_int_same_sign(uint256,uint256,uint256) 21 | UnitTest.test_assertApproxEqAbs_uint(uint256,uint256,uint256) 22 | UnitTest.test_assertApproxEqRel_int_same_sign_unit() 23 | UnitTest.test_assertApproxEqRel_int_zero_cases_unit() 24 | UnitTest.test_assertApproxEqRel_uint_unit() 25 | UnitTest.test_assertEq_address_err() 26 | UnitTest.test_assertEq_bool_err() 27 | UnitTest.test_assertEq_bytes32_err() 28 | UnitTest.test_assertEq_err() 29 | UnitTest.test_assertEq_error_string() 30 | UnitTest.test_assertEq_int256_err() 31 | UnitTest.test_assertEq() 32 | UnitTest.test_assertEq(address,address) 33 | UnitTest.test_assertEq(bool,bool) 34 | UnitTest.test_assertEq(bytes32,bytes32) 35 | UnitTest.test_assertEq(int256,int256) 36 | UnitTest.test_assertFalse_err() 37 | UnitTest.test_assertFalse(bool) 38 | UnitTest.test_assertGt_assertGe(int256,int256) 39 | UnitTest.test_assertGt_assertGe(uint256,uint256) 40 | UnitTest.test_assertLt_assertLe_int_concrete() 41 | UnitTest.test_assertLt_assertLe(int256,int256) 42 | UnitTest.test_assertLt_assertLe(uint256,uint256) 43 | UnitTest.test_assertNotEq_address_err() 44 | UnitTest.test_assertNotEq_bool_err() 45 | UnitTest.test_assertNotEq_bytes32_err() 46 | UnitTest.test_assertNotEq_err() 47 | UnitTest.test_assertNotEq_int256_err() 48 | UnitTest.test_assertNotEq() 49 | UnitTest.test_assertNotEq(address,address) 50 | UnitTest.test_assertNotEq(bool,bool) 51 | UnitTest.test_assertNotEq(bytes32,bytes32) 52 | UnitTest.test_assertNotEq(int256,int256) 53 | UnitTest.test_assertTrue_err() 54 | UnitTest.test_assertTrue(bool) 55 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/end-to-end-prove-show: -------------------------------------------------------------------------------- 1 | ForgetBranchTest.test_forgetBranch(uint256) 2 | RandomVarTest.test_custom_names() 3 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/end-to-end-prove-skip: -------------------------------------------------------------------------------- 1 | UnitTest.test_assert_eq_address_darray_err() 2 | UnitTest.test_assert_eq_bool_darray_err() 3 | UnitTest.test_assert_eq_bytes32_darray_err() 4 | UnitTest.test_assert_eq_int256_darray_err() 5 | UnitTest.test_assert_eq_uint256_darray_err() 6 | UnitTest.test_assertApproxEqAbs_int_opp_sign_err() 7 | UnitTest.test_assertApproxEqAbs_int_opp_sign(uint256,uint256,uint256) 8 | UnitTest.test_assertApproxEqAbs_int_same_sign_err() 9 | UnitTest.test_assertApproxEqAbs_int_zero_cases_err() 10 | UnitTest.test_assertApproxEqAbs_int_zero_cases(uint256,uint256) 11 | UnitTest.test_assertApproxEqAbs_uint_err() 12 | UnitTest.test_assertApproxEqRel_int_opp_sign_err() 13 | UnitTest.test_assertApproxEqRel_int_opp_sign_unit() 14 | UnitTest.test_assertApproxEqRel_int_same_sign_err() 15 | UnitTest.test_assertApproxEqRel_int_zero_cases_err() 16 | UnitTest.test_assertApproxEqRel_uint_err() 17 | UnitTest.test_assertEq_address_err() 18 | UnitTest.test_assertEq_bool_err() 19 | UnitTest.test_assertEq_bytes32_err() 20 | UnitTest.test_assertEq_err() 21 | UnitTest.test_assertEq_error_string() 22 | UnitTest.test_assertEq_int256_err() 23 | UnitTest.test_assertFalse_err() 24 | UnitTest.test_assertGt_assertGe(int256,int256) 25 | UnitTest.test_assertLt_assertLe_int_concrete() 26 | UnitTest.test_assertLt_assertLe(int256,int256) 27 | UnitTest.test_assertNotEq_address_err() 28 | UnitTest.test_assertNotEq_bool_err() 29 | UnitTest.test_assertNotEq_bytes32_err() 30 | UnitTest.test_assertNotEq_err() 31 | UnitTest.test_assertNotEq_int256_err() 32 | UnitTest.test_assertTrue_err() -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry-bmc-all: -------------------------------------------------------------------------------- 1 | BMCBoundTest.testBound() 2 | BMCLoopsTest.test_countdown_concrete() 3 | BMCLoopsTest.test_countdown_symbolic(uint256) 4 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry-bmc-skip: -------------------------------------------------------------------------------- 1 | BMCLoopsTest.test_countdown_symbolic(uint256) 2 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry-dependency-all: -------------------------------------------------------------------------------- 1 | AddConst.applyOp(uint256) 2 | ArithmeticCallTest.test_double_add(uint256,uint256) 3 | ArithmeticCallTest.test_double_add_double_sub(uint256,uint256) 4 | ArithmeticCallTest.test_double_add_sub_external(uint256,uint256,uint256) 5 | ArithmeticContract.add(uint256,uint256) 6 | ArithmeticContract.add_sub_external(uint256,uint256,uint256) 7 | CallableStorageContract.str() 8 | CallableStorageTest.test_str() 9 | CSETest.test_add_const(uint256,uint256) 10 | CSETest.test_identity(uint256,uint256) 11 | ConstructorTest.test_contract_call() 12 | ContractFieldTest.testEscrowToken() 13 | Enum.enum_argument_range(uint8) 14 | Enum.enum_storage_range() 15 | Enum.init 16 | TGovernance.getEscrowTokenTotalSupply() 17 | Identity.applyOp(uint256) 18 | Identity.identity(uint256) 19 | ImportedContract.set(uint256) 20 | ImportedContract.add(uint256) 21 | ImportedContract.count() 22 | InterfaceTagTest.testInterface() 23 | ConstructorTest.init 24 | ImportedContract.init 25 | StaticCallContract.set(uint256) 26 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry-dependency-skip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runtimeverification/kontrol/28d44863fbae232e3ab1e6677fda3af843917150/src/tests/integration/test-data/foundry-dependency-skip -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry-fail: -------------------------------------------------------------------------------- 1 | AssertTest.test_assert_false() 2 | AssertTest.testFail_assert_true() 3 | AssertTest.testFail_expect_revert() 4 | AssertTest.test_failing_branch(uint256) 5 | AssertTest.test_revert_branch(uint256,uint256) 6 | AssumeTest.test_assume_false(uint256,uint256) 7 | AssumeTest.testFail_assume_false(uint256,uint256) 8 | ImmutableVarsTest.test_run_deployment(uint256) 9 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry-init-code: -------------------------------------------------------------------------------- 1 | InitCodeTest.test_init() 2 | InitCodeTest.testFail_init() 3 | ConstructorArgsTest.test_constructor_args() 4 | ConstructorTest.test_constructor() 5 | ConstructorTest.testFail_constructor() 6 | ConstructorTest.run_constructor() 7 | ExternalNestedLibraryTest.testExtLibs() -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry-init-code-skip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runtimeverification/kontrol/28d44863fbae232e3ab1e6677fda3af843917150/src/tests/integration/test-data/foundry-init-code-skip -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry-minimize: -------------------------------------------------------------------------------- 1 | AssertTest.test_assert_false() 2 | AssertTest.testFail_expect_revert() 3 | AssertTest.test_failing_branch(uint256) 4 | AssertTest.test_revert_branch(uint256,uint256) 5 | MergeKCFGTest.test_branch_merge(uint256,uint256,bool) 6 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry-minimize-merge: -------------------------------------------------------------------------------- 1 | MergeKCFGTest.test_branch_merge(uint256,uint256,bool) -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry-prove-with-gas: -------------------------------------------------------------------------------- 1 | GasTest.testInfiniteGas() 2 | GasTest.testSetGas() 3 | StoreTest.testGasLoadColdVM() 4 | StoreTest.testGasLoadWarmUp() 5 | StoreTest.testGasLoadWarmVM() 6 | StoreTest.testGasStoreColdVM() 7 | StoreTest.testGasStoreWarmUp() 8 | StoreTest.testGasStoreWarmVM() -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry-show: -------------------------------------------------------------------------------- 1 | AssertTest.test_assert_false() 2 | AssertTest.test_assert_true() 3 | AssertTest.checkFail_assert_false() 4 | AssertTest.testFail_assert_true() 5 | AssertTest.testFail_expect_revert() 6 | AssertTest.test_failing_branch(uint256) 7 | AssertTest.test_revert_branch(uint256,uint256) 8 | AssumeTest.test_assume_false(uint256,uint256) 9 | AssumeTest.testFail_assume_false(uint256,uint256) 10 | AssumeTest.testFail_assume_true(uint256,uint256) 11 | BMCBoundTest.testBound() 12 | SetUpDeployTest.test_extcodesize() 13 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry-trace-all: -------------------------------------------------------------------------------- 1 | AccountParamsTest.testDealConcrete(),true,true,true 2 | AddrTest.test_addr_true(),true,false,true 3 | BlockParamsTest.testWarp(uint256),false,false,false -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry-trace-skip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runtimeverification/kontrol/28d44863fbae232e3ab1e6677fda3af843917150/src/tests/integration/test-data/foundry-trace-skip -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | src = 'src' 3 | out = 'out' 4 | test = 'test' 5 | extra_output = ['storageLayout', 'abi', 'evm.methodIdentifiers', 'evm.deployedBytecode.object', 'devdoc'] 6 | rpc_endpoints = { optimism = "https://optimism.alchemyapi.io/v2/...", mainnet = "${RPC_MAINNET}" } 7 | # Required to maintain lemmas compatibility after upgrading from nightly-a0a002020be4c40946fe122fe6ff752b21cb2885 8 | optimizer = true -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/src/ArithmeticContract.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | contract ArithmeticContract{ 5 | function add(uint256 x, uint256 y) external pure returns (uint256 z) { 6 | z = x + y; 7 | } 8 | 9 | function addi(uint256 x, int128 y) external pure returns (uint256 z) { 10 | z = uint(int(x) + y); 11 | } 12 | 13 | function sub(uint256 x, uint256 y) external pure returns (uint256 z) { 14 | z = x - y; 15 | } 16 | 17 | function subi(uint256 x, int128 y) external pure returns (uint256 z) { 18 | z = uint(int(x) - y); 19 | } 20 | 21 | function add_sub_external(uint256 x, uint256 y, uint256 z) external view returns (uint256 res) { 22 | uint256 sum = this.add(x, y); 23 | res = sum - z; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/src/Branches.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | 5 | // CSE challenge: multiple branches that slow down the verification 6 | contract Branches{ 7 | function applyOp(uint256 x, uint256 y, bool z) public returns (uint256) { 8 | if (z) { 9 | return x + y; 10 | } else { 11 | return x * y; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/src/ContractToRecordState.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // This file is meant to record state udpates with kontrol load-state (without the --from-state-diff option) 3 | pragma solidity ^0.8.13; 4 | 5 | import {Test} from "forge-std/Test.sol"; 6 | 7 | contract Counter { 8 | uint256 public number; 9 | 10 | function setNumber(uint256 newNumber) public { 11 | number = newNumber; 12 | } 13 | 14 | function increment() public { 15 | number++; 16 | } 17 | } 18 | 19 | // To produce the test file run from the foundry root the following command (after uncommenting vm.dumpState below): 20 | // forge script src/ContractToRecordState.sol:RecordedCounter --sig recordExecutionWithDumpState 21 | // And then run, from the foundry root dir: 22 | // kontrol load-state LoadStateDump ../dumpState.json --output-dir src 23 | contract RecordedCounter is Test { 24 | Counter counter1; 25 | Counter counter2; 26 | 27 | function recordExecutionWithDumpState() public { 28 | string memory dumpStateFile = "../dumpState.json"; 29 | 30 | counter1 = new Counter(); 31 | counter2 = new Counter(); 32 | 33 | counter1.setNumber(1); 34 | counter2.setNumber(2); 35 | vm.deal(address(counter1), 1 ether); 36 | vm.deal(address(counter2), 2 ether); 37 | // Commented since we're running an old forge-std version (v1.6.0) 38 | // vm.dumpState(dumpStateFile); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/src/EmitContract.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | contract ExpectEmit { 5 | event Transfer(address indexed from, address indexed to, uint256 amount); 6 | 7 | function t() public { 8 | emit Transfer(msg.sender, address(1337), 1337); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/src/LoadStateDiff.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // This file was autogenerated by running `kontrol load-state`. Do not edit this file manually. 3 | 4 | pragma solidity ^0.8.13; 5 | 6 | import { Vm } from "forge-std/Vm.sol"; 7 | 8 | import { LoadStateDiffCode } from "./LoadStateDiffCode.sol"; 9 | 10 | contract LoadStateDiff is LoadStateDiffCode { 11 | // Test contract address, 0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496 12 | address private constant FOUNDRY_TEST_ADDRESS = 0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496; 13 | // Cheat code address, 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D 14 | address private constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code")))); 15 | Vm private constant vm = Vm(VM_ADDRESS); 16 | 17 | address internal constant acc0Address = 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f; 18 | 19 | 20 | function recreateState() public { 21 | bytes32 slot; 22 | bytes32 value; 23 | vm.etch(acc0Address, acc0Code); 24 | slot = hex'0000000000000000000000000000000000000000000000000000000000000000'; 25 | value = hex'0000000000000000000000000000000000000000000000000000000000000003'; 26 | vm.store(acc0Address, slot, value); 27 | } 28 | 29 | 30 | function _notExternalAddress(address user) public pure { 31 | vm.assume(user != FOUNDRY_TEST_ADDRESS); 32 | vm.assume(user != VM_ADDRESS); 33 | vm.assume(user != acc0Address); 34 | } 35 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/src/LoadStateDiffCode.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // This file was autogenerated by running `kontrol load-state`. Do not edit this file manually. 3 | 4 | pragma solidity ^0.8.13; 5 | 6 | contract LoadStateDiffCode { 7 | bytes constant internal acc0Code = hex'6080604052348015600f57600080fd5b5060043610603c5760003560e01c80633fb5c1cb1460415780638381f58a146053578063d09de08a14606d575b600080fd5b6051604c3660046083565b600055565b005b605b60005481565b60405190815260200160405180910390f35b6051600080549080607c83609b565b9190505550565b600060208284031215609457600080fd5b5035919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820360f2577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b506001019056fea164736f6c634300080f000a'; 8 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/src/LoadStateDump.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // This file was autogenerated by running `kontrol load-state`. Do not edit this file manually. 3 | 4 | pragma solidity ^0.8.13; 5 | 6 | import { Vm } from "forge-std/Vm.sol"; 7 | 8 | import { LoadStateDumpCode } from "./LoadStateDumpCode.sol"; 9 | 10 | contract LoadStateDump is LoadStateDumpCode { 11 | // Test contract address, 0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496 12 | address private constant FOUNDRY_TEST_ADDRESS = 0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496; 13 | // Cheat code address, 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D 14 | address private constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code")))); 15 | Vm private constant vm = Vm(VM_ADDRESS); 16 | 17 | address internal constant acc0Address = 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f; 18 | address internal constant acc1Address = 0x2e234DAe75C793f67A35089C9d99245E1C58470b; 19 | 20 | 21 | function recreateState() public { 22 | bytes32 slot; 23 | bytes32 value; 24 | vm.etch(acc0Address, acc0Code); 25 | vm.deal(acc0Address, 1000000000000000000); 26 | slot = hex'0000000000000000000000000000000000000000000000000000000000000000'; 27 | value = hex'0000000000000000000000000000000000000000000000000000000000000001'; 28 | vm.store(acc0Address, slot, value); 29 | vm.etch(acc1Address, acc1Code); 30 | vm.deal(acc1Address, 2000000000000000000); 31 | slot = hex'0000000000000000000000000000000000000000000000000000000000000000'; 32 | value = hex'0000000000000000000000000000000000000000000000000000000000000002'; 33 | vm.store(acc1Address, slot, value); 34 | } 35 | 36 | 37 | function _notExternalAddress(address user) public pure { 38 | vm.assume(user != FOUNDRY_TEST_ADDRESS); 39 | vm.assume(user != VM_ADDRESS); 40 | vm.assume(user != acc0Address); 41 | vm.assume(user != acc1Address); 42 | } 43 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/src/LoadStateDumpCode.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | // This file was autogenerated by running `kontrol load-state`. Do not edit this file manually. 3 | 4 | pragma solidity ^0.8.13; 5 | 6 | contract LoadStateDumpCode { 7 | bytes constant internal acc0Code = hex'6080604052348015600f57600080fd5b5060043610603c5760003560e01c80633fb5c1cb1460415780638381f58a146053578063d09de08a14606d575b600080fd5b6051604c3660046083565b600055565b005b605b60005481565b60405190815260200160405180910390f35b6051600080549080607c83609b565b9190505550565b600060208284031215609457600080fd5b5035919050565b60006001820160ba57634e487b7160e01b600052601160045260246000fd5b506001019056fea2646970667358221220c8a96684004f604cf8378bb0bdec95bf1529b5dac4599543eb798b5e5f9a966f64736f6c634300080d0033'; 8 | bytes constant internal acc1Code = hex'6080604052348015600f57600080fd5b5060043610603c5760003560e01c80633fb5c1cb1460415780638381f58a146053578063d09de08a14606d575b600080fd5b6051604c3660046083565b600055565b005b605b60005481565b60405190815260200160405180910390f35b6051600080549080607c83609b565b9190505550565b600060208284031215609457600080fd5b5035919050565b60006001820160ba57634e487b7160e01b600052601160045260246000fd5b506001019056fea2646970667358221220c8a96684004f604cf8378bb0bdec95bf1529b5dac4599543eb798b5e5f9a966f64736f6c634300080d0033'; 9 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/src/Mock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.8.13; 2 | 3 | contract Mock { 4 | uint256 state = 0; 5 | 6 | function numberA() public pure returns (uint256) { 7 | return 1; 8 | } 9 | 10 | function numberB() public pure returns (uint256) { 11 | return 2; 12 | } 13 | 14 | function add(uint256 a, uint256 b) public pure returns (uint256) { 15 | return a + b; 16 | } 17 | 18 | function pay(uint256 a) public payable returns (uint256) { 19 | return a; 20 | } 21 | 22 | function noReturnValue() public { 23 | // Does nothing of value, but also ensures that Solidity will 100% 24 | // generate an `extcodesize` check. 25 | state += 1; 26 | } 27 | 28 | function getRevert() public view returns (uint256) { 29 | require(state != 0, "State is 0"); 30 | return state; 31 | } 32 | } 33 | 34 | contract NestedMock { 35 | Mock private inner; 36 | 37 | constructor(Mock _inner) { 38 | inner = _inner; 39 | } 40 | 41 | function sum() public view returns (uint256) { 42 | return inner.numberA() + inner.numberB(); 43 | } 44 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/src/MyIERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity =0.8.13; 3 | 4 | interface MyIERC20 { 5 | function totalSupply() external view returns (uint256); 6 | 7 | function transfer(address recipient, uint256 amount) external returns (bool); 8 | 9 | function decimals() external view returns (uint8); 10 | 11 | function symbol() external view returns (string memory); 12 | 13 | function balanceOf(address) external view returns (uint256); 14 | 15 | function transferFrom( 16 | address sender, 17 | address recipient, 18 | uint256 amount 19 | ) external returns (bool); 20 | 21 | function approve(address spender, uint256 value) external returns (bool); 22 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/src/MyToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | contract MyToken{ 5 | address public token; 6 | mapping (address => uint256) public balances; 7 | 8 | constructor(address sometoken) { 9 | token = sometoken; 10 | } 11 | 12 | function balanceOf(address user) external view returns (uint256) { 13 | return balances[user]; 14 | } 15 | 16 | receive() external payable {} 17 | 18 | function pay(address user) external payable returns (uint256) { 19 | balances[user]+=msg.value; 20 | return balances[user]; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/src/OwnerOnlyUp.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | error Unauthorized(); 5 | 6 | contract OwnerUpOnly { 7 | address public immutable owner; 8 | uint256 public count; 9 | 10 | constructor() { 11 | owner = msg.sender; 12 | } 13 | 14 | function increment() external { 15 | if (msg.sender != owner) { 16 | revert Unauthorized(); 17 | } 18 | count++; 19 | } 20 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/src/Portal.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.8.13; 2 | 3 | library Types { 4 | struct OutputRootProof { 5 | bytes32 version; 6 | bytes32 stateRoot; 7 | bytes32 messagePasserStorageRoot; 8 | bytes32 latestBlockhash; 9 | } 10 | 11 | struct WithdrawalTransaction { 12 | uint256 nonce; 13 | address sender; 14 | address target; 15 | uint256 value; 16 | uint256 gasLimit; 17 | bytes data; 18 | } 19 | } 20 | 21 | contract Portal { 22 | bool paused; 23 | 24 | /// @notice Emitted when a withdrawal transaction is proven. 25 | event WithdrawalProven(address indexed from, address indexed to); 26 | 27 | /// @notice Reverts when paused. 28 | modifier whenNotPaused() { 29 | require(paused == false, "Portal: paused"); 30 | _; 31 | } 32 | 33 | constructor() { 34 | paused = true; 35 | } 36 | 37 | /// @notice Proves a withdrawal transaction. 38 | function proveWithdrawalTransaction( 39 | Types.WithdrawalTransaction memory _tx, 40 | uint256 _l2OutputIndex, 41 | Types.OutputRootProof calldata _outputRootProof, 42 | bytes[] calldata _withdrawalProof 43 | ) 44 | external 45 | whenNotPaused 46 | { 47 | // Emit a `WithdrawalProven` event. 48 | emit WithdrawalProven(_tx.sender, _tx.target); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/src/Prank.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | error Unauthorized(); 5 | 6 | contract Prank { 7 | address public immutable owner; 8 | uint256 public count; 9 | 10 | constructor() { 11 | owner = msg.sender; 12 | } 13 | 14 | function add(uint256 value) external { 15 | require(msg.sender == owner, "Only owner"); 16 | count += value; 17 | } 18 | 19 | function subtract(uint256 value) external { 20 | require(tx.origin == address(0)); 21 | require(count >= value); 22 | count -= value; 23 | } 24 | 25 | function msgSender() public view returns (address) { 26 | return msg.sender; 27 | } 28 | 29 | function txOrigin() public view returns (address) { 30 | return tx.origin; 31 | } 32 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/src/Safe.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | contract Safe { 5 | receive() external payable {} 6 | 7 | function withdraw() external { 8 | payable(msg.sender).transfer(address(this).balance); 9 | } 10 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/src/TestNumber.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import {Test, console} from "forge-std/Test.sol"; 5 | 6 | contract TestNumber is Test{ 7 | uint256 public testNumber ; 8 | 9 | constructor(uint256 initial){ 10 | testNumber = initial; 11 | } 12 | 13 | function t(uint256 a) public returns (uint256) { 14 | uint256 b = 0; 15 | testNumber = a; 16 | emit log_string("here"); 17 | return b; 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/src/Token.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | contract Token { 5 | uint256 x; 6 | mapping(address => uint256) balances; 7 | mapping(address => mapping(address => uint256)) allowances; 8 | string name; 9 | uint64 y; 10 | uint96 z; 11 | uint32 a; 12 | 13 | struct Foo { 14 | uint256 bar; 15 | address baz; 16 | uint48 boo; 17 | uint48 frob; 18 | uint48[] bills; 19 | } 20 | 21 | mapping(address => Foo) foos; 22 | 23 | function _move(address src, address dst, uint256 amount) internal { 24 | balances[src] = balances[src] - amount; 25 | balances[dst] = balances[dst] + amount; 26 | } 27 | 28 | function transfer(address dst, uint256 amount) external { 29 | _move(msg.sender, dst, amount); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/src/cse/Binary.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import { UIntBinaryOp } from "./OperatorInterfaces.sol"; 5 | import { Identity } from "./Unary.sol"; 6 | 7 | // CSE challenge: storage variable of a contract type 8 | // CSE challenge: cross-contract external function call 9 | contract Add is UIntBinaryOp { 10 | Identity id; 11 | 12 | function applyOp(uint256 x, uint256 y) external view returns (uint256 result) { 13 | return id.applyOp(x) + id.applyOp(y); 14 | } 15 | 16 | } 17 | 18 | // CSE challenge: storage variable of a contract type 19 | // CSE challenge: cross-contract external function call 20 | contract Sub is UIntBinaryOp { 21 | Identity id; 22 | 23 | function applyOp(uint256 x, uint256 y) external view returns (uint256 result) { 24 | return id.applyOp(x) - id.applyOp(y); 25 | } 26 | } 27 | 28 | // CSE challenge: storage variable of a contract type 29 | // CSE challenge: cross-contract external function call 30 | // CSE challenge: bounded reasoning 31 | contract Multiply is UIntBinaryOp { 32 | Add adder; 33 | 34 | function applyOp(uint256 x, uint256 y) external view returns (uint256 result) { 35 | for (result = 0; y > 0; y--) { 36 | result = adder.applyOp(result, x); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/src/cse/OperatorInterfaces.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | interface UIntUnaryOp { 5 | function applyOp(uint256 x) external view returns (uint256); 6 | } 7 | 8 | interface UIntBinaryOp { 9 | function applyOp(uint256 x, uint256 y) external view returns (uint256 result); 10 | } 11 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/src/cse/Unary.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import { UIntUnaryOp } from "./OperatorInterfaces.sol"; 5 | 6 | // CSE challenge: external function call 7 | contract Identity is UIntUnaryOp { 8 | 9 | function identity(uint256 x) external pure returns (uint256) { 10 | return x; 11 | } 12 | 13 | function applyOp(uint256 x) external view returns (uint256) { 14 | return this.identity(x); 15 | } 16 | } 17 | 18 | // CSE challenge: storage variable of a basic type 19 | contract AddConst is UIntUnaryOp { 20 | uint256 c; 21 | 22 | function setConst(uint256 x) external { 23 | c = x; 24 | } 25 | 26 | function applyOp(uint256 x) external view returns (uint256) { 27 | return x + c; 28 | } 29 | } 30 | 31 | // CSE challenge: storage variable of an interface type 32 | // this is higher-order and not possible in general 33 | // one way of handling this is instantiating the `UIntUnaryOp` 34 | // interface with specific contracts that implement it 35 | // CSE challenge: cross-contract external function call 36 | contract Iterate is UIntUnaryOp { 37 | UIntUnaryOp f; 38 | 39 | function applyOp(uint256 x) external view returns (uint256) { 40 | return f.applyOp((f.applyOp(x))); 41 | } 42 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/src/cse/WETH9.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | // CSE challenge: initialised contract variables 5 | // CSE challenge: global variables 6 | // CSE challenge: mappings in storage 7 | 8 | contract WETH9 { 9 | string public name = "Wrapped Ether"; 10 | string public symbol = "WETH"; 11 | uint8 public decimals = 18; 12 | 13 | event Approval(address indexed src, address indexed guy, uint256 wad); 14 | event Transfer(address indexed src, address indexed dst, uint256 wad); 15 | event Deposit(address indexed dst, uint256 wad); 16 | event Withdrawal(address indexed src, uint256 wad); 17 | 18 | mapping(address => uint256) public balanceOf; 19 | mapping(address => mapping(address => uint256)) public allowance; 20 | 21 | fallback() external payable { 22 | deposit(); 23 | } 24 | 25 | function deposit() public payable { 26 | balanceOf[msg.sender] += msg.value; 27 | emit Deposit(msg.sender, msg.value); 28 | } 29 | 30 | function withdraw(uint256 wad) public { 31 | require(balanceOf[msg.sender] >= wad); 32 | balanceOf[msg.sender] -= wad; 33 | payable(msg.sender).transfer(wad); 34 | emit Withdrawal(msg.sender, wad); 35 | } 36 | 37 | function totalSupply() public view returns (uint256) { 38 | return address(this).balance; 39 | } 40 | 41 | function approve(address guy, uint256 wad) public returns (bool) { 42 | allowance[msg.sender][guy] = wad; 43 | emit Approval(msg.sender, guy, wad); 44 | return true; 45 | } 46 | 47 | function transfer(address dst, uint256 wad) public returns (bool) { 48 | return transferFrom(msg.sender, dst, wad); 49 | } 50 | 51 | function transferFrom(address src, address dst, uint256 wad) public returns (bool) { 52 | require(balanceOf[src] >= wad); 53 | 54 | if (src != msg.sender && allowance[src][msg.sender] != type(uint256).max) { 55 | require(allowance[src][msg.sender] >= wad); 56 | allowance[src][msg.sender] -= wad; 57 | } 58 | 59 | balanceOf[src] -= wad; 60 | balanceOf[dst] += wad; 61 | 62 | emit Transfer(src, dst, wad); 63 | 64 | return true; 65 | } 66 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/src/duplicates/1/DuplicateName.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | contract DuplicateName { 5 | function duplicateNamedFunction() public {} 6 | } 7 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/src/duplicates/2/DuplicateName.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | contract DuplicateName { 5 | function duplicateNamedFunction() public {} 6 | } 7 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/AccountParamsTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | contract AccountParamsTest is Test { 7 | 8 | function testDealConcrete() public { 9 | vm.deal(address(505), 256); 10 | assertEq(address(505).balance, 256); 11 | } 12 | 13 | function testDealSymbolic(uint256 value) public { 14 | vm.deal(address(328), value); 15 | assertEq(address(328).balance, value); 16 | } 17 | 18 | function testEtchConcrete() public { 19 | bytes memory code = bytes("this should be EVM bytecode"); 20 | vm.etch(address(124), code); 21 | assertEq(address(124).code, code); 22 | } 23 | 24 | function testEtchSymbolic(bytes calldata code) public { 25 | vm.etch(address(124), code); 26 | assertEq(address(124).code, code); 27 | } 28 | 29 | function testNonceSymbolic(uint64 newNonce) public { 30 | uint64 oldNonce = vm.getNonce(address(this)); 31 | vm.assume(newNonce > oldNonce); 32 | vm.setNonce(address(this), newNonce); 33 | assert(vm.getNonce(address(this)) == newNonce); 34 | } 35 | 36 | function test_GetNonce_true() public { 37 | uint64 nonce = vm.getNonce(address(this)); 38 | assert(nonce == 1); 39 | } 40 | 41 | function test_getNonce_unknownSymbolic(address addr) public { 42 | vm.assume(addr != address(vm)); 43 | vm.assume(addr != address(this)); 44 | vm.assume(addr != address(0x3fAB184622Dc19b6109349B94811493BF2a45362)); 45 | vm.assume(addr != address(0x4e59b44847b379578588920cA78FbF26c0B4956C)); 46 | uint64 nonce = vm.getNonce(addr); 47 | assert(nonce == 0); 48 | } 49 | 50 | function test_GetNonce_false() public { 51 | uint64 nonce = vm.getNonce(address(100)); 52 | assertEq(nonce, 10); 53 | } 54 | 55 | function testFail_GetNonce_true() public { 56 | uint64 nonce = vm.getNonce(address(0)); 57 | assertEq(nonce, 10); 58 | } 59 | 60 | function testFail_GetNonce_false() public { 61 | uint64 nonce = vm.getNonce(address(this)); 62 | assertEq(nonce, 1); 63 | } 64 | 65 | function test_Nonce_ExistentAddress() public { 66 | vm.setNonce(address(this), 100); 67 | uint64 nonce = vm.getNonce(address(this)); 68 | assert(nonce == 100); 69 | } 70 | 71 | function test_Nonce_NonExistentAddress() public { 72 | vm.setNonce(address(100), 100); 73 | uint64 nonce = vm.getNonce(address(100)); 74 | assert(nonce == 100); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/AddrTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | import "kontrol-cheatcodes/KontrolCheats.sol"; 6 | 7 | contract AddrTest is Test, KontrolCheats { 8 | 9 | function test_addr_true() public { 10 | address alice = vm.addr(1); 11 | assertEq(alice, 0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf); 12 | } 13 | 14 | function test_addr_false() public { 15 | address alice = vm.addr(0); 16 | } 17 | 18 | function testFail_addr_true() public { 19 | address alice = vm.addr(115792089237316195423570985008687907852837564279074904382605163141518161494337); 20 | } 21 | 22 | function testFail_addr_false() public { 23 | address alice = vm.addr(1); 24 | assertEq(alice, 0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf); 25 | } 26 | 27 | function test_addr_symbolic(uint256 pk) public { 28 | vm.assume(pk != 0); 29 | vm.assume(pk < 115792089237316195423570985008687907852837564279074904382605163141518161494337); 30 | address alice = vm.addr(pk); 31 | assert(true); 32 | } 33 | 34 | function test_notBuiltinAddress_concrete() public { 35 | assertTrue(notBuiltinAddress(address(110))); 36 | } 37 | 38 | function test_notBuiltinAddress_symbolic(address addr) public { 39 | vm.assume(addr != address(728815563385977040452943777879061427756277306518)); 40 | vm.assume(addr != address(645326474426547203313410069153905908525362434349)); 41 | assertTrue(notBuiltinAddress(addr)); 42 | } 43 | 44 | function test_builtInAddresses() public { 45 | assertEq(address(this), address(728815563385977040452943777879061427756277306518)); 46 | assertEq(address(vm), address(645326474426547203313410069153905908525362434349)); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/AllowChangesTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | import "kontrol-cheatcodes/KontrolCheats.sol"; 6 | 7 | contract ValueStore { 8 | uint256 public slot0; 9 | uint256 public slot1; 10 | 11 | function changeSlot0(uint256 newValue) public { 12 | slot0 = newValue; 13 | } 14 | 15 | function changeSlot1(uint256 newValue) public { 16 | slot1 = newValue; 17 | } 18 | } 19 | 20 | contract AllowChangesTest is Test, KontrolCheats { 21 | ValueStore canChange; 22 | ValueStore cannotChange; 23 | 24 | function setUp() public { 25 | canChange = new ValueStore(); 26 | cannotChange = new ValueStore(); 27 | } 28 | 29 | function testAllow() public { 30 | kevm.allowCallsToAddress(address(canChange)); 31 | kevm.allowChangesToStorage(address(canChange), 0); 32 | 33 | canChange.changeSlot0(85); 34 | } 35 | 36 | function testAllowSymbolic() public { 37 | kevm.symbolicStorage(address(canChange)); 38 | 39 | kevm.allowCallsToAddress(address(canChange)); 40 | kevm.allowChangesToStorage(address(canChange), 0); 41 | canChange.changeSlot0(85); 42 | } 43 | function testFailAllowCallsToAddress() public { 44 | kevm.allowCallsToAddress(address(canChange)); 45 | 46 | cannotChange.changeSlot0(10245); 47 | } 48 | 49 | function testFailAllowChangesToStorage() public { 50 | kevm.allowChangesToStorage(address(canChange), 0); 51 | 52 | canChange.changeSlot1(23452); 53 | } 54 | 55 | function testAllow_fail() public { 56 | kevm.allowCallsToAddress(address(canChange)); 57 | kevm.allowChangesToStorage(address(canChange), 0); 58 | 59 | canChange.changeSlot1(234521); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/Ambiguous.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | contract AmbiguousTest { 5 | function test_assert_true() public pure { 6 | assert(true); 7 | } 8 | 9 | function test_assert_true(uint256) public pure { 10 | assert(true); 11 | } 12 | 13 | function test_assert_true(uint8) public pure { 14 | assert(true); 15 | } 16 | 17 | function test_array_type(uint256) public { 18 | assert(true); 19 | } 20 | 21 | function test_array_type(uint256[] calldata numbers) public { 22 | assert(true); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/ArithmeticCall.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | import "../src/ArithmeticContract.sol"; 6 | 7 | contract ArithmeticCallTest is Test { 8 | ArithmeticContract arith; 9 | 10 | function setUp() external { 11 | arith = new ArithmeticContract(); 12 | } 13 | 14 | function test_double_add(uint x, uint y) external { 15 | uint z = arith.add(x, y); 16 | z = arith.add(z, y); 17 | assert(z > x); 18 | } 19 | 20 | function test_double_add_double_sub(uint x, uint y) external { 21 | uint a = arith.add(x, y); 22 | a = arith.add(a, y); 23 | uint b = arith.sub(x, y); 24 | b = arith.sub(b, y); 25 | assert (a != b); 26 | } 27 | 28 | function test_double_add_sub_external(uint x, uint y, uint z) external { 29 | uint a = arith.add_sub_external(x, y, z); 30 | a = arith.add_sub_external(a, y, z); 31 | assert(a > x); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/AssumeTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | contract AssumeTest is Test { 7 | 8 | function test_assume_true(uint256 a, uint256 b) public { 9 | vm.assume(a == b); 10 | assertEq(a, b); 11 | } 12 | 13 | function test_assume_false(uint256 a, uint256 b) public { 14 | vm.assume(a != b); 15 | assertEq(a, b); 16 | } 17 | 18 | function testFail_assume_true(uint256 a, uint256 b) public { 19 | vm.assume(a != b); 20 | assertEq(a, b); 21 | } 22 | 23 | function testFail_assume_false(uint256 a, uint256 b) public { 24 | vm.assume(a == b); 25 | assertEq(a, b); 26 | } 27 | 28 | function test_assume_staticCall(bool a) public { 29 | address(vm).staticcall(abi.encodeWithSignature("assume(bool)", a)); 30 | assert(a); 31 | } 32 | 33 | function test_multi_assume(address alice, address bob) public { 34 | vm.assume(alice != address(120209876281281145568259943)); 35 | vm.assume(alice != address(137122462167341575662000267002353578582749290296)); 36 | vm.assume(alice != address(645326474426547203313410069153905908525362434349)); 37 | vm.assume(alice != address(728815563385977040452943777879061427756277306518)); 38 | 39 | vm.assume(bob != address(120209876281281145568259943)); 40 | vm.assume(bob != address(137122462167341575662000267002353578582749290296)); 41 | vm.assume(bob != address(645326474426547203313410069153905908525362434349)); 42 | vm.assume(bob != address(728815563385977040452943777879061427756277306518)); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/BMCBound.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.13; 3 | 4 | import {Test} from "forge-std/Test.sol"; 5 | import {KontrolCheats} from "kontrol-cheatcodes/KontrolCheats.sol"; 6 | 7 | contract BMCBoundTest is Test, KontrolCheats { 8 | uint x; 9 | 10 | function setUp() public { 11 | uint256 i = freshUInt256(); 12 | for (uint j = 0; j < i; j++) { 13 | x += 1; 14 | } 15 | } 16 | 17 | function testBound() public { 18 | assertLe(x, 3); 19 | } 20 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/BMCLoops.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | contract BMCLoopsTest is Test { 7 | 8 | function test_countdown_concrete() public returns (uint) { 9 | uint n = 3; 10 | while (n > 0) { 11 | n = n - 1; 12 | } 13 | assert(n == 0); 14 | } 15 | 16 | function test_countdown_symbolic(uint n) public returns (uint) { 17 | vm.assume(n <= 3); 18 | while (n > 0) { 19 | n = n - 1; 20 | } 21 | assert(n == 0); 22 | } 23 | 24 | function test_bmc(uint256 n) public { 25 | uint256 x = 0; 26 | for (uint256 i = 0; i < n; ++i) { 27 | x += 1; 28 | } 29 | assertEq(x, n); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/BlockParamsTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | contract BlockParamsTest is Test { 7 | 8 | function testWarp(uint256 time) public { 9 | vm.warp(time); 10 | assertEq(block.timestamp, time); 11 | } 12 | 13 | function testRoll(uint256 newHeight) public { 14 | vm.roll(newHeight); 15 | assertEq(block.number, newHeight); 16 | } 17 | 18 | function testFee(uint256 newFee) public { 19 | vm.fee(newFee); 20 | assertEq(block.basefee, newFee); 21 | } 22 | 23 | function testChainId(uint256 newChainId) public { 24 | vm.chainId(newChainId); 25 | assertEq(block.chainid, newChainId); 26 | } 27 | 28 | function testCoinBase() public { 29 | address coinBase = 0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8; 30 | vm.coinbase(coinBase); 31 | assertEq(block.coinbase, coinBase); 32 | } 33 | 34 | function testBlockNumber() public { 35 | uint256 x = block.number; 36 | assert(x >= 0); 37 | } 38 | } 39 | 40 | contract RollTest is Test { 41 | function setUp() external { 42 | vm.roll(123); 43 | } 44 | 45 | function test_roll_setup() external { 46 | assert(block.number == 123); 47 | 48 | } 49 | } 50 | 51 | contract WarpTest is Test { 52 | function setUp() external { 53 | vm.warp(1641070800); 54 | } 55 | 56 | function test_warp_setup() external { 57 | assert(block.timestamp == 1641070800); 58 | } 59 | } 60 | 61 | contract FeeTest is Test { 62 | function setUp() external { 63 | vm.fee(25 gwei); 64 | } 65 | 66 | function test_fee_setup() external { 67 | assert(block.basefee == 25 gwei); 68 | 69 | } 70 | } 71 | 72 | contract ChainIdTest is Test { 73 | function setUp() external { 74 | vm.chainId(31337); 75 | } 76 | 77 | function test_chainid_setup() external { 78 | assert(block.chainid == 31337); 79 | 80 | } 81 | } 82 | 83 | contract CoinBaseTest is Test { 84 | function setUp() external { 85 | vm.coinbase(0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8); 86 | } 87 | 88 | function test_coinbase_setup() external { 89 | assert(block.coinbase == 0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8); 90 | 91 | } 92 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/BroadcastTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "src/TestNumber.sol"; 5 | import "forge-std/Test.sol"; 6 | 7 | contract BroadcastTest is Test { 8 | address ACCOUNT_A; 9 | address ACCOUNT_B; 10 | 11 | function setUp() public { 12 | ACCOUNT_A = 0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8; 13 | ACCOUNT_B = 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D; 14 | } 15 | 16 | function testDeploy() public { 17 | vm.broadcast(ACCOUNT_A); 18 | TestNumber test = new TestNumber(10); 19 | // this won't generate tx to sign 20 | uint256 b = test.t(4); 21 | assertEq(b,0); 22 | // this will 23 | vm.broadcast(ACCOUNT_B); 24 | test.t(5); 25 | } 26 | 27 | function deployOther() public { 28 | vm.startBroadcast(ACCOUNT_A); 29 | TestNumber test = new TestNumber(10); 30 | 31 | // will trigger a transaction 32 | test.t(1); 33 | 34 | vm.stopBroadcast(); 35 | } 36 | 37 | function deployNoArgs() public { 38 | // broadcast the next call 39 | vm.broadcast(); 40 | TestNumber test1 = new TestNumber(5); 41 | test1.t(0); 42 | 43 | // broadcast all calls between this line and `stopBroadcast` 44 | vm.startBroadcast(); 45 | TestNumber test2 = new TestNumber(20); 46 | test2.t(25); 47 | vm.stopBroadcast(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/CSE.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | import "src/cse/Unary.sol"; 7 | import "src/cse/Binary.sol"; 8 | import "src/cse/WETH9.sol"; 9 | 10 | contract CSETest is Test { 11 | Identity i; 12 | AddConst c; 13 | Multiply m; 14 | 15 | function setUp() external { 16 | i = new Identity(); 17 | c = new AddConst(); 18 | m = new Multiply(); 19 | } 20 | 21 | // CSE challenge: External function call 22 | function test_identity(uint256 x, uint256 y) external view { 23 | vm.assume(x < 2 ** 64 && y < 2 ** 64); 24 | uint256 z = i.applyOp(x) + i.applyOp(y) + i.applyOp(y); 25 | assert(z == x + 2 * y); 26 | } 27 | 28 | function test_add_const(uint256 x, uint256 y) external { 29 | vm.assume(x < 2 ** 64 && y < 2 ** 64); 30 | c.setConst(x); 31 | uint256 z = c.applyOp(y); 32 | assert(z == x + y); 33 | } 34 | } 35 | 36 | contract StaticCallContract { 37 | uint x; 38 | 39 | function set(uint y) public { 40 | x = y; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/CallableStorageTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | import "kontrol-cheatcodes/KontrolCheats.sol"; 6 | 7 | contract CallableStorageContract { 8 | uint public num; 9 | string public str; 10 | 11 | constructor(string memory a) payable { 12 | str = a; 13 | } 14 | } 15 | 16 | contract CallableStorageTest is Test, KontrolCheats { 17 | CallableStorageContract member_contract; 18 | 19 | function setUp() public { 20 | member_contract = new CallableStorageContract("Test String"); 21 | } 22 | 23 | function test_str() public { 24 | assertEq(member_contract.str(), "Test String"); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/ConstructorTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | contract ImportedContract { 7 | uint256 public count; 8 | 9 | constructor() payable { 10 | count = 5; 11 | } 12 | 13 | function set(uint256 x) public { 14 | if(count < 3){ 15 | return; 16 | } 17 | count = x; 18 | } 19 | 20 | function add(uint256 x) public payable { 21 | count = count + x; 22 | } 23 | } 24 | 25 | contract ConstructorTest is Test { 26 | bool flag = true; 27 | ImportedContract member_contract; 28 | 29 | constructor() { 30 | member_contract = new ImportedContract(); 31 | member_contract.set(4321); 32 | } 33 | 34 | function test_constructor() public { 35 | assert(flag); 36 | } 37 | 38 | function testFail_constructor() public { 39 | assert(!flag); 40 | } 41 | 42 | function run_constructor() public { 43 | assert(flag); 44 | } 45 | 46 | function test_contract_call() public { 47 | assert(flag); 48 | ImportedContract local_contract = new ImportedContract(); 49 | local_contract.set(5432); 50 | 51 | member_contract.add(3); 52 | assertEq(member_contract.count(), 4324); 53 | 54 | local_contract.add(5); 55 | assertEq(local_contract.count(), 5437); 56 | } 57 | } 58 | 59 | contract ConstructorArgsTest is Test { 60 | bool public flag; 61 | uint256 public count; 62 | 63 | constructor(bool _flag, uint256 _count) { 64 | flag = _flag; 65 | count = _count; 66 | } 67 | 68 | function test_constructor_args() public { 69 | // `flag` is assigned a symbolic value in constructor 70 | vm.assume(flag); 71 | // the node is not vacuous 72 | assert(flag); 73 | } 74 | } 75 | 76 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/Contract.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | contract ContractTest is Test { 7 | function testExample() public { 8 | assertTrue(true); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/ContractBTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | contract ContractBTest is Test { 7 | uint256 testNumber; 8 | 9 | function setUp() public { 10 | testNumber = 42; 11 | } 12 | 13 | function testNumberIs42() public { 14 | assertEq(testNumber, 42); 15 | } 16 | 17 | function testFailSubtract43() public { 18 | testNumber -= 43; 19 | } 20 | 21 | function testCannotSubtract43() public { 22 | vm.expectRevert(stdError.arithmeticError); 23 | testNumber -= 43; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/ContractFieldTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | import {Test} from "forge-std/Test.sol"; 4 | 5 | contract TToken { 6 | uint128 private totalSupply; 7 | 8 | constructor(uint128 _totalSupply) { 9 | totalSupply = _totalSupply; 10 | } 11 | 12 | function getTotalSupply() public returns (uint256) { 13 | return 32 + uint256(totalSupply); 14 | } 15 | } 16 | 17 | contract TEscrow { 18 | bool spacer; 19 | TToken token; 20 | 21 | constructor(address _token) { 22 | token = TToken(_token); 23 | } 24 | 25 | function getTokenTotalSupply() public returns (uint256) { 26 | return token.getTotalSupply() + 13; 27 | } 28 | } 29 | 30 | contract TGovernance { 31 | TEscrow escrow; 32 | 33 | constructor(address _escrow) { 34 | escrow = TEscrow(_escrow); 35 | } 36 | 37 | function getEscrowTokenTotalSupply() public returns (uint256) { 38 | return escrow.getTokenTotalSupply(); 39 | } 40 | } 41 | 42 | contract ContractFieldTest is Test { 43 | TToken token; 44 | TEscrow escrow; 45 | 46 | function setUp() public { 47 | token = new TToken(12300); 48 | escrow = new TEscrow(address(token)); 49 | } 50 | 51 | /* Calling `getTokenTotalSupply` will summarize `totalSupply` and 52 | include `TestToken token` into the list of accounts in `getTokenTotalSupply`'s summary 53 | */ 54 | function testEscrowToken() public { 55 | assert(escrow.getTokenTotalSupply() == 12345); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/CopyStorage.t.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.8.13; 2 | 3 | import "forge-std/Test.sol"; 4 | 5 | import "kontrol-cheatcodes/KontrolCheats.sol"; 6 | 7 | contract CopyStorageContract { 8 | uint256 public x; 9 | } 10 | 11 | contract CopyStorageTest is Test, KontrolCheats { 12 | CopyStorageContract csc_1; 13 | CopyStorageContract csc_2; 14 | 15 | function _storeUInt256(address contractAddress, uint256 slot, uint256 value) internal { 16 | vm.store(contractAddress, bytes32(slot), bytes32(value)); 17 | } 18 | 19 | function setUp() public { 20 | csc_1 = new CopyStorageContract(); 21 | csc_2 = new CopyStorageContract(); 22 | } 23 | 24 | function testCopyStorage() public { 25 | // Make the storage of first contract symbolic 26 | kevm.symbolicStorage(address(csc_1)); 27 | // and explicitly put a constrained symbolic value into the slot for `x` 28 | uint256 x_1 = uint256(kevm.freshUInt(32)); 29 | _storeUInt256(address(csc_1), 0, x_1); 30 | 31 | // `x` of second contract is uninitialized 32 | assert(csc_2.x() == 0); 33 | // Copy storage from first to second contract 34 | kevm.copyStorage(address(csc_1), address(csc_2)); 35 | // `x` of second contract is now the `x` of the first 36 | assert(csc_2.x() == x_1); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/CounterTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity >=0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | import "kontrol-cheatcodes/KontrolCheats.sol"; 6 | 7 | contract Counter { 8 | uint256 public number; 9 | 10 | function setNumber(uint256 newNumber) public { 11 | number = newNumber; 12 | } 13 | 14 | function increment() public { 15 | number++; 16 | } 17 | } 18 | 19 | contract CounterTest is Test, KontrolCheats { 20 | Counter public counter; 21 | 22 | // function setUp() public { 23 | // counter = new Counter(); 24 | // counter.setNumber(0); 25 | // } 26 | 27 | function testIncrement() public { 28 | counter = new Counter(); 29 | counter.setNumber(0); 30 | counter.increment(); 31 | assertEq(counter.number(), 1); 32 | } 33 | 34 | function testSetNumber(uint256 x) public { 35 | //setUp(); 36 | counter = new Counter(); 37 | counter.setNumber(0); 38 | counter.setNumber(x); 39 | assertEq(counter.number(), x); 40 | } 41 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/DynamicTypes.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | struct DeploymentParameters { 7 | Parameters[] parameters; 8 | uint256 counter; 9 | } 10 | 11 | struct Parameters { 12 | uint256 value; 13 | } 14 | 15 | contract ArrayStructContract { 16 | uint256 public parameterLength; 17 | 18 | // NatSpec comments in constructors aren't supported, but `kontrol build` shouldn't fail 19 | constructor(DeploymentParameters memory _deploymentParameters) { 20 | parameterLength = _deploymentParameters.parameters.length; 21 | } 22 | } 23 | 24 | contract DynamicTypesTest is Test { 25 | 26 | struct ComplexType { 27 | uint256 id; 28 | bytes content; 29 | } 30 | 31 | struct ComplexNestedType { 32 | ComplexType[] values; 33 | uint256 nonce; 34 | } 35 | 36 | struct ComplexTypeArray { 37 | address[] assets; 38 | uint256[] maxAmountsIn; 39 | bytes userData; 40 | bool fromInternalBalance; 41 | } 42 | 43 | /// @custom:kontrol-bytes-length-equals content: 10000, 44 | /// @custom:kontrol-array-length-equals ba: 10, 45 | /// @custom:kontrol-bytes-length-equals ba: 600, 46 | function test_complex_type(ComplexType calldata ctValues, bytes[] calldata ba) public { 47 | require (ba.length == 10, "DynamicTypes: invalid length for bytes[]"); 48 | assert(ctValues.content.length == 10000); 49 | assert(ba[8].length == 600); 50 | } 51 | 52 | /// @custom:kontrol-array-length-equals ctValues: 10, 53 | /// @custom:kontrol-bytes-length-equals content: 10000, 54 | /// @custom:kontrol-array-length-equals ba: 10, 55 | /// @custom:kontrol-bytes-length-equals ba: 600, 56 | function test_complex_type_array(ComplexType[] calldata ctValues, bytes[] calldata ba, uint256 offset) public { 57 | require (ctValues.length == 10, "DynamicTypes: invalid length for ComplexType[]"); 58 | require (ba.length == 10, "DynamicTypes: invalid length for bytes[]"); 59 | vm.assume(offset < 10); 60 | assert(ctValues[offset].content.length == 10000); 61 | assert(ba[offset].length == 600); 62 | } 63 | 64 | /// @custom:kontrol-array-length-equals ctValues: 10, 65 | /// @custom:kontrol-bytes-length-equals content: 10000, 66 | function test_dynamic_struct_array(ComplexType[] calldata ctValues) public { 67 | require (ctValues.length == 10, "DynamicTypes: invalid length for ComplexType[]"); 68 | assert(ctValues[8].content.length == 10000); 69 | } 70 | 71 | function test_nested_struct_array(ComplexType[][] memory ctValues) public { 72 | require(ctValues[0].length == 1, "DynamicTypes: invalid default lengths for two-dimensional ComplexType[][]"); 73 | } 74 | 75 | function test_dynamic_nested_struct_array(ComplexNestedType memory cntValues) public { 76 | require(cntValues.values.length == 1, "DynamicTypes: invalid default length for ComplexType[] in ComplexNestedType"); 77 | } 78 | 79 | function test_dynamic_struct_nested_array(ComplexTypeArray memory ctaValues) public { 80 | require(ctaValues.assets.length == 1, "DynamicTypes: invalid default length for assets in ComplexTypeArray"); 81 | require(ctaValues.maxAmountsIn.length == 1, "DynamicTypes: invalid default length for maxAmountsIn in ComplexTypeArray"); 82 | } 83 | 84 | function test_dynamic_byte_read(bytes memory data, uint256 offset) public { 85 | uint8 mydata = uint8(data[offset]); 86 | vm.assume(mydata < 3); 87 | assertTrue(mydata == 2 || mydata == 1 || mydata == 0); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/EmitContractTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | import "src/EmitContract.sol"; 6 | 7 | contract EmitContractTest is Test { 8 | event Transfer(address indexed from, address indexed to, uint256 amount); 9 | 10 | function testExpectEmit() public { 11 | ExpectEmit emitter = new ExpectEmit(); 12 | // Check that topic 1, topic 2, and data are the same as the following emitted event. 13 | // Checking topic 3 here doesn't matter, because `Transfer` only has 2 indexed topics. 14 | vm.expectEmit(true, true, false, true); 15 | // The event we expect 16 | emit Transfer(address(this), address(1337), 1337); 17 | // The event we get 18 | emitter.t(); 19 | } 20 | 21 | function testExpectEmitDoNotCheckData() public { 22 | ExpectEmit emitter = new ExpectEmit(); 23 | // Check topic 1 and topic 2, but do not check data 24 | vm.expectEmit(true, true, false, false); 25 | // The event we expect 26 | emit Transfer(address(this), address(1337), 1338); 27 | // The event we get 28 | emitter.t(); 29 | } 30 | 31 | function testExpectEmitCheckEmitter() public { 32 | ExpectEmit emitter = new ExpectEmit(); 33 | vm.expectEmit(true, true, false, true, address(emitter)); 34 | // The event we expect 35 | emit Transfer(address(this), address(1337), 1337); 36 | // The event we get 37 | emitter.t(); 38 | } 39 | 40 | function testExpectEmitLessTopics() public { 41 | ExpectEmit emitter = new ExpectEmit(); 42 | vm.expectEmit(true, true, true, false); 43 | emit Transfer(address(this), address(1337), 1337); 44 | emitter.t(); 45 | } 46 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/Enum.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | enum Letter { 7 | LETTER_A, 8 | LETTER_B, 9 | LETTER_C, 10 | LETTER_D, 11 | LETTER_E, 12 | LETTER_F 13 | } 14 | 15 | contract EnumContract { 16 | uint256 public count; 17 | Letter public letter; 18 | 19 | constructor() payable { 20 | count = 5; 21 | } 22 | } 23 | 24 | contract Enum { 25 | EnumContract member_contract; 26 | 27 | function enum_storage_range() public view { 28 | assert(uint(member_contract.letter()) <= 5); 29 | assert(uint(member_contract.letter()) >= 0); 30 | } 31 | 32 | function enum_argument_range(Letter letter) public view { 33 | assert(uint(letter) <= 5); 34 | assert(uint(letter) >= 0); 35 | } 36 | 37 | constructor(Letter letter) public { 38 | assert(uint(letter) <= 5); 39 | assert(uint(letter) >= 0); 40 | } 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/ExpectCallTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | import "kontrol-cheatcodes/KontrolCheats.sol"; 6 | 7 | contract Dummy { 8 | function numberA() public pure returns (uint) { 9 | return 200; 10 | } 11 | } 12 | 13 | contract ExpectCallTest is Test, KontrolCheats { 14 | 15 | 16 | function testExpectStaticCall() public { 17 | Dummy dummyContract = new Dummy(); 18 | address addr = address(dummyContract); 19 | bytes memory data = abi.encodeWithSelector(dummyContract.numberA.selector); 20 | uint256 result = 0; 21 | kevm.expectStaticCall(addr, data); 22 | 23 | assembly { 24 | let status := staticcall(16000, addr, add(data, 32), mload(data), 0, 0) 25 | if eq(status, 1) { 26 | if eq(returndatasize(), 32) { 27 | returndatacopy(0, 0, 32) 28 | result := mload(0) 29 | } 30 | } 31 | } 32 | 33 | assert(result == 200); 34 | } 35 | 36 | function testExpectRegularCall() public { 37 | Dummy dummyContract = new Dummy(); 38 | address addr = address(dummyContract); 39 | bytes memory data = abi.encodeWithSelector(dummyContract.numberA.selector); 40 | uint256 result = 0; 41 | kevm.expectRegularCall(addr, 0, data); 42 | 43 | assembly { 44 | let status := call(16000, addr, 0, add(data, 32), mload(data), 0, 0) 45 | if eq(status, 1) { 46 | if eq(returndatasize(), 32) { 47 | returndatacopy(0, 0, 32) 48 | result := mload(0) 49 | } 50 | } 51 | } 52 | 53 | assert(result == 200); 54 | } 55 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/ExternalLibTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | library SimpleMath { 7 | struct LibStruct { 8 | uint256 elementOne; 9 | address elementTwo; 10 | } 11 | 12 | function structInput(LibStruct memory s) public pure returns (uint256) { 13 | return s.elementOne; 14 | } 15 | 16 | function square(uint256 x) public pure returns (uint256) { 17 | return x * x; 18 | } 19 | 20 | function sum(uint256 a, uint256 b) external pure returns (uint256 res) { 21 | res = a + b; 22 | } 23 | } 24 | 25 | contract ExternalLibTest is Test { 26 | function testSquare(uint256 n) public { 27 | vm.assume(msg.sender == address(110)); 28 | vm.assume(n <= type(uint128).max); 29 | assertEq(SimpleMath.square(n), n * n); 30 | } 31 | 32 | function testSum() public { 33 | vm.assume(msg.sender == address(110)); 34 | uint256 x = 3; 35 | uint256 y = 7; 36 | assertEq(SimpleMath.sum(x, y), 10); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/ExternalNestedLibraryTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.13; 3 | 4 | import {Test, console} from "forge-std/Test.sol"; 5 | 6 | library LibrarySum { 7 | function sum(uint256 a, uint256 b) external pure returns (uint256 res) { 8 | res = a + b; 9 | } 10 | } 11 | 12 | library LibraryEq { 13 | function eq(uint256 a, uint256 b, uint256 c) internal returns (bool res) { 14 | uint256 sum = LibrarySum.sum(a, b); 15 | return (sum == c); 16 | } 17 | } 18 | 19 | contract ExternalNestedLibraryTest is Test { 20 | uint256 public z = 10; 21 | 22 | function testExtLibs() public { 23 | uint256 x = 3; 24 | uint256 y = 7; 25 | bool res = LibraryEq.eq(x, y, z); 26 | assert(res); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/FfiTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | contract FfiTest is Test { 7 | 8 | function setUp() public{ 9 | string memory key = "FOO"; 10 | string memory val = "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000a72756e74696d6556617200000000000000000000000000000000000000000000"; 11 | vm.setEnv(key, val); 12 | } 13 | 14 | function testffi() public { 15 | string[] memory inputs = new string[](3); 16 | inputs[0] = "echo"; 17 | inputs[1] = "-n"; 18 | // ABI encoded "gm", as a string 19 | inputs[2] = vm.toString(abi.encode("gm")); 20 | //inputs[2] = "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002676d000000000000000000000000000000000000000000000000000000000000"; 21 | bytes memory res = vm.ffi(inputs); 22 | string memory output = abi.decode(res, (string)); 23 | assertEq(output, "gm"); 24 | } 25 | 26 | 27 | function testFFIFOO() public { 28 | string[] memory inputs = new string[](3); 29 | inputs[0] = "bash"; 30 | inputs[1] = "-c"; 31 | inputs[2] = "echo -n $FOO"; 32 | 33 | bytes memory res = vm.ffi(inputs); 34 | string memory output = abi.decode(res, (string)); 35 | assertEq(output, "runtimeVar"); 36 | } 37 | 38 | function testFFIScript() public { 39 | string[] memory inputs = new string[](2); 40 | inputs[0] = "bash"; 41 | inputs[1] = "test/myscript.sh"; 42 | 43 | bytes memory res = vm.ffi(inputs); 44 | string memory output = abi.decode(res, (string)); 45 | assertEq(output, "runtimeVar"); 46 | } 47 | 48 | function testFFIScript2() public { 49 | string[] memory inputs = new string[](2); 50 | inputs[0] = "bash"; 51 | inputs[1] = "test/script.sh"; 52 | 53 | bytes memory res = vm.ffi(inputs); 54 | string memory output = abi.decode(res, (string)); 55 | assertEq(output, "true"); 56 | } 57 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/FilesTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | contract FilesTest is Test { 7 | 8 | function testReadWriteFile() public { 9 | string memory contents = vm.readFile("./test/file.txt"); 10 | vm.writeFile("./test/filecopy.txt", contents); 11 | string memory contentsCopy = vm.readFile("./test/filecopy.txt"); 12 | 13 | assertEq(contents, contentsCopy); 14 | } 15 | 16 | function testReadWriteLine() public { 17 | string memory line = vm.readLine("./test/file.txt"); 18 | vm.writeLine("./test/fileline.txt", line); 19 | line = vm.readLine("./test/file.txt"); 20 | assertEq(line, "for testing"); 21 | 22 | vm.closeFile("./test/file.txt"); 23 | line = vm.readLine("./test/file.txt"); 24 | assertEq(line, "This is a file"); 25 | } 26 | 27 | function testFailRemoveFile() public { 28 | string memory contents = vm.readFile("./test/file.txt"); 29 | vm.writeFile("./test/filecopy2.txt", contents); 30 | vm.removeFile("./test/filecopy2.txt"); 31 | vm.readFile("./test/filecopy2.txt"); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/ForkTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | contract ForkTest is Test { 7 | 8 | function testCreateFork() public { 9 | uint256 forkId = vm.createFork("https://eth-mainnet.public.blastapi.io"); 10 | vm.selectFork(forkId); 11 | 12 | assertGt(block.number, 15223854); // as of time of writing 13 | } 14 | 15 | function testCreateForkBlock() public { 16 | uint256 forkId = vm.createFork("https://eth-mainnet.public.blastapi.io", 15223849); 17 | vm.selectFork(forkId); 18 | 19 | assertEq(block.number, 15223849); 20 | } 21 | 22 | function testCreateSelectFork() public { 23 | vm.createSelectFork("https://eth-mainnet.public.blastapi.io"); 24 | assertGt(block.number, 15223854); 25 | } 26 | 27 | function testCreateSelectForkBlock() public { 28 | vm.createSelectFork("https://eth-mainnet.public.blastapi.io", 15223849); 29 | assertEq(block.number, 15223849); 30 | } 31 | 32 | function testActiveFork() public { 33 | uint256 mainnetForkId = vm.createFork("https://eth-mainnet.public.blastapi.io"); 34 | uint256 binanceForkId = vm.createFork("https://bscrpc.com"); 35 | 36 | assert(mainnetForkId != binanceForkId); 37 | 38 | vm.selectFork(mainnetForkId); 39 | assertEq(vm.activeFork(), mainnetForkId); 40 | 41 | vm.selectFork(binanceForkId); 42 | assertEq(vm.activeFork(), binanceForkId); 43 | } 44 | 45 | function testRollFork() public { 46 | uint256 forkId = vm.createFork("https://bscrpc.com"); 47 | vm.selectFork(forkId); 48 | 49 | assertGt(block.number, 19918933); // 50 | vm.rollFork(19918777); 51 | 52 | assertEq(block.number, 19918777); 53 | } 54 | 55 | function testRollForkId() public { 56 | uint256 forkId = vm.createFork("https://api.avax.network/ext/bc/C/rpc"); 57 | vm.rollFork(forkId, 17871134); 58 | 59 | vm.selectFork(forkId); 60 | //console.log(block.number); 61 | assertEq(block.number, 17871134); 62 | } 63 | 64 | function testRPCUrl() public { 65 | string memory url = vm.rpcUrl("optimism"); 66 | assertEq(url, "https://optimism.alchemyapi.io/v2/..."); 67 | } 68 | 69 | function testRPCUrlRevert() public { 70 | vm.expectRevert("Failed to resolve env var `RPC_MAINNET`: environment variable not found"); 71 | vm.rpcUrl("mainnet"); 72 | } 73 | 74 | function testAllRPCUrl() public { 75 | //this line is to comment after I know how to set the environment variable RPC_MAINNET 76 | vm.expectRevert("Failed to resolve env var `RPC_MAINNET`: environment variable not found"); 77 | string[2][] memory allUrls = vm.rpcUrls(); 78 | assertEq(allUrls.length, 2); 79 | 80 | string[2] memory val = allUrls[0]; 81 | assertEq(val[0], "mainnet"); 82 | 83 | string[2] memory env = allUrls[1]; 84 | assertEq(env[0], "optimism"); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/FreshBytes.t.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.8.13; 2 | 3 | import "forge-std/Test.sol"; 4 | 5 | import "kontrol-cheatcodes/KontrolCheats.sol"; 6 | 7 | contract FreshBytesTest is Test, KontrolCheats { 8 | bytes1 local_byte; 9 | bytes local_bytes; 10 | 11 | uint256 constant length_limit = 72; 12 | 13 | function manip_symbolic_bytes(bytes memory b) public { 14 | uint middle = b.length / 2; 15 | b[middle] = hex'aa'; 16 | } 17 | 18 | function test_symbolic_bytes_1() public { 19 | uint256 length = uint256(kevm.freshUInt(1)); 20 | vm.assume (0 < length); 21 | vm.assume (length <= length_limit); 22 | bytes memory fresh_bytes = kevm.freshBytes(length); 23 | uint256 index = uint256(kevm.freshUInt(1)); 24 | vm.assume(index < length); 25 | 26 | local_byte = fresh_bytes[index]; 27 | assertEq(fresh_bytes[index], local_byte); 28 | } 29 | 30 | function test_symbolic_bytes_2() public { 31 | uint256 length = uint256(kevm.freshUInt(1)); 32 | vm.assume (0 < length); 33 | vm.assume (length <= length_limit); 34 | bytes memory fresh_bytes = kevm.freshBytes(length); 35 | 36 | local_bytes = fresh_bytes; 37 | assertEq(fresh_bytes, local_bytes); 38 | } 39 | 40 | function test_symbolic_bytes_3() public { 41 | uint256 length = uint256(kevm.freshUInt(1)); 42 | vm.assume (0 < length); 43 | vm.assume (length <= length_limit); 44 | bytes memory fresh_bytes = kevm.freshBytes(length); 45 | 46 | manip_symbolic_bytes(fresh_bytes); 47 | assertEq(hex'aa', fresh_bytes[length / 2]); 48 | } 49 | 50 | function test_symbolic_bytes_length(uint256 l) public { 51 | vm.assume(0 < l); 52 | vm.assume(l <= length_limit); 53 | bytes memory fresh_bytes = kevm.freshBytes(l); 54 | assertEq(fresh_bytes.length, l); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/FreshInt.t.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.8.13; 2 | 3 | import "forge-std/Test.sol"; 4 | 5 | import "kontrol-cheatcodes/KontrolCheats.sol"; 6 | 7 | contract FreshCheatcodes is Test, KontrolCheats { 8 | int128 constant min = -170141183460469231731687303715884105728; 9 | int128 constant max = 170141183460469231731687303715884105727; 10 | 11 | function test_bool() public { 12 | uint256 fresh_uint256 = kevm.freshBool(); 13 | assertGe(fresh_uint256, 0); 14 | assertLe(fresh_uint256, 1); 15 | } 16 | 17 | function test_int128() public { 18 | int128 val = int128(uint128(kevm.freshUInt(16))); 19 | assertGe(val, min); 20 | assertLe(val, max); 21 | } 22 | 23 | function testFail_int128() public { 24 | int128 val = int128(uint128(kevm.freshUInt(16))); 25 | assertGt(val, max); 26 | } 27 | 28 | function test_address() public { 29 | address fresh_address = kevm.freshAddress(); 30 | assertNotEq(fresh_address, address(this)); 31 | assertNotEq(fresh_address, address(vm)); 32 | } 33 | 34 | function test_freshUints(uint8 x) public { 35 | vm.assume(0 < x); 36 | vm.assume(x <= 32); 37 | uint256 freshUint = kevm.freshUInt(x); 38 | 39 | assert(0 <= freshUint); 40 | assert(freshUint < 2 ** (8 * x)); 41 | } 42 | 43 | function test_freshSymbolicWord() public { 44 | uint256 freshUint192 = freshUInt192(); 45 | 46 | assert(0 <= freshUint192); 47 | assert(freshUint192 <= type(uint192).max); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/GasTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | import "kontrol-cheatcodes/KontrolCheats.sol"; 6 | 7 | contract GasTest is Test, KontrolCheats { 8 | function testInfiniteGas() public { 9 | // Infinite gas is used by default 10 | uint256 gasLeftBefore = gasleft(); 11 | uint256 x = 345; 12 | uint256 y = 928; 13 | uint256 z = y - x; 14 | uint256 gasLeftAfter = gasleft(); 15 | assert(gasLeftBefore <= gasLeftAfter); 16 | assert(gasLeftAfter <= gasLeftBefore); 17 | } 18 | 19 | function testSetGas() public { 20 | kevm.setGas(33000); 21 | uint256 gasLeftBefore = gasleft(); 22 | uint256 gasLeftAfter = gasleft(); 23 | assert(gasLeftBefore > gasLeftAfter); 24 | } 25 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/GetCodeTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | import "src/MyToken.sol"; 6 | 7 | 8 | contract GetCodeTest is Test { 9 | MyToken myToken; 10 | 11 | 12 | function setUp() public{ 13 | myToken = new MyToken(address(1234)); 14 | } 15 | 16 | function testGetCode() public { 17 | bytes memory args = abi.encode(address(1234)); 18 | vm.label(address(1234), "exampleAddress"); 19 | bytes memory bytecode = abi.encodePacked(vm.getCode("MyToken.sol:MyToken"), args); 20 | address anotherAddress; 21 | assembly { 22 | anotherAddress := create(0, add(bytecode, 0x20), mload(bytecode)) 23 | } 24 | 25 | assertEq0(address(myToken).code, anotherAddress.code); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/ImmutableVarsTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | import "kontrol-cheatcodes/KontrolCheats.sol"; 6 | 7 | contract ImmutableVarsContract { 8 | uint256 public immutable y; 9 | 10 | constructor(uint256 _y) { 11 | y = _y; 12 | } 13 | } 14 | 15 | contract ImmutableVarsTest is Test { 16 | function test_run_deployment(uint256 x) public returns (bool) { 17 | ImmutableVarsContract c = new ImmutableVarsContract(x); 18 | assert(c.y() == 85); 19 | } 20 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/InitCode.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | contract InitCodeTest is Test { 7 | 8 | uint a = 4; 9 | uint b = 100; 10 | uint c = 100; 11 | 12 | constructor() public payable { 13 | b = 2; 14 | c = 200; 15 | } 16 | 17 | function setUp() public { 18 | c = 1; 19 | } 20 | 21 | function test_init() public { 22 | assertEq(a + b + c, 7); 23 | } 24 | function testFail_init() public { 25 | assertEq(a + b + c, 8); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/InitCodeBranch.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | import "kontrol-cheatcodes/KontrolCheats.sol"; 6 | 7 | contract InitCodeBranchTest is Test, KontrolCheats { 8 | 9 | uint a; 10 | uint b; 11 | 12 | constructor() public payable { 13 | kevm.symbolicStorage(address(this)); 14 | if(a <= 10) { 15 | b = 1; 16 | } 17 | else { 18 | b = 2; 19 | } 20 | } 21 | 22 | function test_branch() public { 23 | assertEq(b, 1); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/InterfaceTagTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.13; 3 | 4 | import {Test, console} from "forge-std/Test.sol"; 5 | 6 | contract ERC20 { 7 | function totalSupply() public view returns (uint256) { return 15; } 8 | } 9 | 10 | interface IERC20 { 11 | /** 12 | * @dev Returns the value of tokens in existence. 13 | */ 14 | function totalSupply() external view returns (uint256); 15 | } 16 | 17 | contract InterfaceContract { 18 | /// @custom:kontrol-instantiate-interface ERC20 19 | IERC20 token; 20 | 21 | constructor(address _token) { 22 | token = IERC20(_token); 23 | } 24 | 25 | function callToken() public returns (uint256) { return token.totalSupply();} 26 | } 27 | 28 | contract InterfaceTagTest is Test { 29 | InterfaceContract intContract; 30 | 31 | function setUp() public { 32 | ERC20 token = new ERC20(); 33 | intContract = new InterfaceContract(address(token)); 34 | } 35 | 36 | function testInterface() public { 37 | assert(intContract.callToken() == 15); 38 | } 39 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/LabelTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | contract LabelTest is Test { 7 | 8 | function testLabel() public { 9 | vm.label(address(0), "Zero Address"); 10 | //Just to check test trace 11 | assert(true); 12 | } 13 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/Merge.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | import "kontrol-cheatcodes/KontrolCheats.sol"; 6 | 7 | contract MergeTest is Test, KontrolCheats { 8 | uint y; 9 | 10 | function test_branch_merge(uint x) public { 11 | if (x < 10) { 12 | y = 0; 13 | } else { 14 | y = 1; 15 | } 16 | assert(y < 2); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/MergeKCFGTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | import "src/Branches.sol"; 6 | 7 | contract MergeKCFGTest is Test { 8 | Branches c; 9 | 10 | function setUp() external { 11 | c = new Branches(); 12 | } 13 | 14 | function test_branch_merge(uint256 x, uint256 y, bool z) external{ 15 | vm.assume(x <= type(uint256).max - y); 16 | try c.applyOp(x, y, z) returns (uint256 res) { 17 | // This check will fail if the backend cannot recover the preds in the merged postcondition 18 | // If so, assert res == x + y | res == x * y will pass 19 | // If so, we should not always use merge_node, but provide both on need. 20 | if (z) { 21 | assert(res == x + y); 22 | } else { 23 | assert(res == x * y); 24 | } 25 | } catch { 26 | assert(x != 0 && 2 ** 62 / x < y && !z); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/MethodDisambiguate.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | contract MethodDisambiguateTest is Test { 7 | 8 | function getNumber(uint256 x) public returns(uint256) { 9 | assertEq(x, x); 10 | return 1; 11 | } 12 | 13 | function getNumber(uint32 x) public returns(uint256) { 14 | assertEq(x, x); 15 | return 2; 16 | } 17 | 18 | function test_method_call() public { 19 | uint256 x = 0; 20 | assertEq(1, getNumber(x)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/MockFunction.t.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.8.13; 2 | 3 | import "forge-std/Test.sol"; 4 | 5 | import "kontrol-cheatcodes/KontrolCheats.sol"; 6 | 7 | contract MockFunctionContract { 8 | uint256 public a; 9 | 10 | function mocked_function() public { 11 | a = 321; 12 | } 13 | 14 | function mocked_args_function(uint256 x) public { 15 | a = 321 + x; 16 | } 17 | } 18 | 19 | contract ModelMockFunctionContract { 20 | uint256 public a; 21 | 22 | function mocked_function() public { 23 | a = 123; 24 | } 25 | 26 | function mocked_args_function(uint256 x) public { 27 | a = 123 + x; 28 | } 29 | } 30 | 31 | contract MockFunctionTest is Test, KontrolCheats { 32 | MockFunctionContract my_contract; 33 | ModelMockFunctionContract model_contract; 34 | 35 | function setUp() public { 36 | my_contract = new MockFunctionContract(); 37 | model_contract = new ModelMockFunctionContract(); 38 | } 39 | 40 | function test_mock_function() public { 41 | kevm.mockFunction( 42 | address(my_contract), 43 | address(model_contract), 44 | abi.encodeWithSelector(MockFunctionContract.mocked_function.selector) 45 | ); 46 | my_contract.mocked_function(); 47 | assertEq(my_contract.a(), 123); 48 | } 49 | 50 | function test_mock_function_concrete_args() public { 51 | kevm.mockFunction( 52 | address(my_contract), 53 | address(model_contract), 54 | abi.encodeWithSelector(MockFunctionContract.mocked_args_function.selector, 456) 55 | ); 56 | my_contract.mocked_args_function(456); 57 | assertEq(my_contract.a(), 123 + 456); 58 | 59 | my_contract.mocked_args_function(567); 60 | assertEq(my_contract.a(), 321 + 567); 61 | } 62 | 63 | function test_mock_function_all_args() public { 64 | kevm.mockFunction( 65 | address(my_contract), 66 | address(model_contract), 67 | abi.encodeWithSelector(MockFunctionContract.mocked_args_function.selector) 68 | ); 69 | my_contract.mocked_args_function(678); 70 | assertEq(my_contract.a(), 123 + 678); 71 | 72 | my_contract.mocked_args_function(789); 73 | assertEq(my_contract.a(), 123 + 789); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/NestedArrayStructs.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | interface ProjectConfig { 7 | struct ChainEnv { 8 | string chainName; 9 | string chainIndex; 10 | } 11 | 12 | struct Vault { 13 | string tokenName; 14 | address oracle; 15 | uint256 allowedToTrade; 16 | InputData params; 17 | uint256 reserves; 18 | } 19 | 20 | struct InputData { 21 | uint256 ltv; 22 | uint256 rate; 23 | uint256 exchangeRate; 24 | uint256 utilization; 25 | } 26 | 27 | struct AssetAddresses { 28 | address cToken; 29 | address dToken; 30 | } 31 | 32 | struct VaultWithAddresses { 33 | Vault vault; 34 | AssetAddresses addresses; 35 | } 36 | } 37 | 38 | contract NestedStructArrayTest is Test, ProjectConfig { 39 | // this test branches on dynamically sized calldata and not run in CI; it is only meant to test `kontrol build` 40 | function testVaultSignature(ChainEnv calldata environment, VaultWithAddresses[] memory listings) external { 41 | assert(listings.length == 1); 42 | } 43 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/NestedStructs.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | contract NestedStructsTest is Test { 7 | struct Processor { 8 | Window windows; 9 | } 10 | 11 | struct Window { 12 | Frame[] frames; 13 | bytes32 hash; 14 | } 15 | 16 | struct Frame { 17 | Pointer position; 18 | bytes32 root; 19 | } 20 | 21 | struct Pointer { 22 | PointerType pointerType; 23 | uint256 value; 24 | } 25 | 26 | enum PointerType { 27 | INT32, 28 | INT64 29 | } 30 | 31 | function prove_fourfold_nested_struct(Processor calldata initialProcessor) external pure { 32 | assert(initialProcessor.windows.frames.length == 1); 33 | } 34 | 35 | function prove_fourfold_nested_struct_array(Processor[] calldata initialProcessor) external pure { 36 | assert(initialProcessor[0].windows.frames.length == 1); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/NoImports.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | contract NoImport { 5 | function test_source_map() public pure returns (uint) { 6 | uint x = 0; 7 | uint y = 1; 8 | uint z = 2; 9 | uint a = x + y; 10 | uint b = z - y; 11 | uint c = a * b; 12 | return a + b + c; 13 | } 14 | } 15 | 16 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/OwnerOnlyUpTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | import "src/OwnerOnlyUp.sol"; 6 | 7 | contract OwnerUpOnlyTest is Test { 8 | OwnerUpOnly upOnly; 9 | 10 | function setUp() public { 11 | upOnly = new OwnerUpOnly(); 12 | } 13 | 14 | function testIncrementAsOwner() public { 15 | assertEq(upOnly.count(), 0); 16 | upOnly.increment(); 17 | assertEq(upOnly.count(), 1); 18 | } 19 | 20 | function testFailIncrementAsNotOwner() public { 21 | vm.prank(address(0)); 22 | upOnly.increment(); 23 | } 24 | 25 | function testIncrementAsNotOwner() public { 26 | vm.expectRevert(Unauthorized.selector); 27 | vm.prank(address(0)); 28 | upOnly.increment(); 29 | } 30 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/PortalTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | import "../src/Portal.sol"; 6 | 7 | contract PortalTest is Test { 8 | Portal portalContract; 9 | 10 | function setUp() public { 11 | portalContract = new Portal(); 12 | } 13 | 14 | /// @custom:kontrol-array-length-equals _withdrawalProof: 1, 15 | /// @custom:kontrol-bytes-length-equals _withdrawalProof: 32, 16 | function test_withdrawal_paused( 17 | Types.WithdrawalTransaction memory _tx, 18 | uint256 _l2OutputIndex, 19 | Types.OutputRootProof calldata _outputRootProof, 20 | bytes[] calldata _withdrawalProof 21 | ) 22 | external 23 | { 24 | vm.expectRevert(); 25 | portalContract.proveWithdrawalTransaction(_tx, _l2OutputIndex, _outputRootProof, _withdrawalProof); 26 | } 27 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/PrankTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | import "src/Prank.sol"; 6 | 7 | contract PrankTest is Test { 8 | Prank prankContract; 9 | 10 | function setUp() public { 11 | prankContract = new Prank(); 12 | } 13 | 14 | function testAddAsOwner(uint256 x) public { 15 | assertEq(prankContract.count(), 0); 16 | prankContract.add(x); 17 | assertEq(prankContract.count(), x); 18 | } 19 | 20 | function testFailAddPrank(uint256 x) public { 21 | vm.prank(address(0)); 22 | prankContract.add(x); 23 | } 24 | 25 | function testAddStartPrank(uint256 x) public { 26 | vm.expectRevert(bytes("Only owner")); 27 | vm.startPrank(address(0)); 28 | prankContract.add(x); 29 | assertEq(prankContract.count(), 0); 30 | vm.stopPrank(); 31 | } 32 | 33 | 34 | function testSubtractFail(uint256 x) public { 35 | vm.expectRevert(); 36 | prankContract.subtract(x); 37 | assertEq(prankContract.count(), 0); 38 | } 39 | 40 | function testSubtractAsTxOrigin(uint256 addValue, uint256 subValue) public { 41 | prankContract.add(addValue); 42 | vm.assume(subValue<=addValue); 43 | vm.prank(address(0), address(0)); 44 | prankContract.subtract(subValue); 45 | assertEq(prankContract.count(), addValue-subValue); 46 | } 47 | 48 | function testSubtractStartPrank(uint256 addValue, uint256 subValue) public { 49 | prankContract.add(addValue); 50 | vm.startPrank(address(0),address(0)); 51 | vm.assume(subValue<=addValue); 52 | prankContract.subtract(subValue); 53 | assertEq(prankContract.count(), addValue-subValue); 54 | vm.stopPrank(); 55 | } 56 | 57 | function testSymbolicStartPrank(address addr) public { 58 | vm.startPrank(addr); 59 | assert(prankContract.msgSender() == addr); 60 | vm.stopPrank(); 61 | } 62 | } 63 | 64 | contract PrankTestMsgSender is Test { 65 | Prank public prankcontract; 66 | 67 | function setUp() public { 68 | prankcontract = new Prank(); 69 | vm.prank(address(0)); 70 | } 71 | 72 | function test_msgsender_setup() external { 73 | assert(prankcontract.msgSender() == address(0)); 74 | } 75 | } 76 | 77 | contract PrankTestOrigin is Test { 78 | Prank public prankcontract; 79 | 80 | function setUp() public { 81 | prankcontract = new Prank(); 82 | vm.prank(address(0), address(0)); 83 | } 84 | 85 | function test_origin_setup() external { 86 | assert(prankcontract.txOrigin() == address(0)); 87 | } 88 | } 89 | 90 | contract StartPrankTestMsgSender is Test { 91 | Prank public prankcontract; 92 | 93 | function setUp() public { 94 | prankcontract = new Prank(); 95 | vm.startPrank(address(0)); 96 | } 97 | 98 | function test_startprank_msgsender_setup() external { 99 | assert(prankcontract.msgSender() == address(0)); 100 | } 101 | } 102 | 103 | contract StartPrankTestOrigin is Test { 104 | Prank public prankcontract; 105 | 106 | function setUp() public { 107 | prankcontract = new Prank(); 108 | vm.startPrank(address(0), address(0)); 109 | } 110 | 111 | function test_startprank_origin_setup() external { 112 | assert(prankcontract.txOrigin() == address(0)); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/Preconditions.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity >=0.8.0; 3 | 4 | import "forge-std/Test.sol"; 5 | import "kontrol-cheatcodes/KontrolCheats.sol"; 6 | 7 | contract PreconditionsTest is Test, KontrolCheats { 8 | uint256 n; 9 | 10 | function setUp() public { 11 | kevm.symbolicStorage(address(this)); 12 | vm.assume(n < 10); 13 | } 14 | 15 | function testAssume() public { 16 | assertLt(n, 10); 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/RecordLogsTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | import "src/EmitContract.sol"; 6 | 7 | contract RecordLogsTest is Test { 8 | ExpectEmit emitter; 9 | 10 | function setUp() public { 11 | emitter = new ExpectEmit(); 12 | vm.recordLogs(); 13 | } 14 | 15 | function testRecordLogs() public{ 16 | emitter.t(); 17 | Vm.Log[] memory entries = vm.getRecordedLogs(); 18 | assertEq(entries.length, 1); 19 | assertEq(entries[0].topics[0], keccak256("Transfer(address,address,uint256)")); 20 | assertEq(abi.decode(entries[0].data, (uint256)), 1337); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/SafeTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | import "src/Safe.sol"; 6 | 7 | contract SafeTest is Test { 8 | Safe safe; 9 | 10 | // Needed so the test contract itself can receive ether 11 | // when withdrawing 12 | receive() external payable {} 13 | 14 | function setUp() public { 15 | safe = new Safe(); 16 | } 17 | 18 | function testWithdraw() public { 19 | payable(address(safe)).transfer(1 ether); 20 | uint256 preBalance = address(this).balance; 21 | safe.withdraw(); 22 | uint256 postBalance = address(this).balance; 23 | assertEq(preBalance + 1 ether, postBalance); 24 | } 25 | 26 | function testWithdrawFuzz(uint96 amount) public { 27 | vm.assume(amount > 0.1 ether); 28 | payable(address(safe)).transfer(amount); 29 | uint256 preBalance = address(this).balance; 30 | safe.withdraw(); 31 | uint256 postBalance = address(this).balance; 32 | assertEq(preBalance + amount, postBalance); 33 | } 34 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/SetUp2Test.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | contract Setup2Test is Test { 7 | 8 | uint a; 9 | uint b; 10 | uint c; 11 | 12 | function setUp() public { 13 | a = 1; 14 | b = 2; 15 | c = 3; 16 | } 17 | 18 | function test_setup() public { 19 | assertEq(a + b + c, 6); 20 | } 21 | function testFail_setup() public { 22 | assertEq(a + b + c, 7); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/SetUpDeploy.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | import "src/MyToken.sol"; 6 | 7 | // This experiment covers the basic behavior of the 8 | // test contract constructor and setup function. 9 | // 10 | // In particular, it ensures that the constructor 11 | // and setup functions are called before running 12 | // the tests. 13 | // 14 | // The setup function is called exactly once after 15 | // the constructor function. 16 | // 17 | // Before each test the VM reverts to the post 18 | // setup state. 19 | contract SetUpDeployTest is Test { 20 | 21 | MyToken token; 22 | 23 | function setUp() public{ 24 | token = new MyToken(address(0)); 25 | } 26 | 27 | function test_extcodesize() public { 28 | uint size; 29 | address token_addr = address(token); 30 | assembly { 31 | size := extcodesize(token_addr) 32 | } 33 | assert(size > 0); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/SetUpTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | import "kontrol-cheatcodes/KontrolCheats.sol"; 6 | 7 | // This experiment covers the basic behavior of the 8 | // test contract constructor and setup function. 9 | // 10 | // In particular, it ensures that the constructor 11 | // and setup functions are called before running 12 | // the tests. 13 | // 14 | // The setup function is called exactly once after 15 | // the constructor function. 16 | // 17 | // Before each test the VM reverts to the post 18 | // setup state. 19 | contract SetUpTest is Test, KontrolCheats { 20 | 21 | uint256 counter = 0; 22 | uint256 data; 23 | 24 | constructor () { 25 | counter = 100; 26 | } 27 | 28 | function setUp() public{ 29 | counter++; 30 | data = uint256(kevm.freshUInt(32)); 31 | vm.assume(data < 42); 32 | } 33 | 34 | function testSetUpCalled() public { 35 | assertEq(counter, 101); 36 | } 37 | 38 | // We also want to cover a symbolic case 39 | function testSetUpCalledSymbolic(uint256 x) public { 40 | assertEq(counter, 101); 41 | // The following assertion is only here so that 42 | // x is used and not thrown away by the optimizer 43 | assertEq(x, x); 44 | } 45 | 46 | function testSetupData() public { 47 | assert(data < 42); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/SignTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | contract SignTest is Test { 7 | 8 | function testSign() public { 9 | address alice = vm.addr(1); 10 | bytes32 hash = keccak256("Signed by Alice"); 11 | (uint8 v, bytes32 r, bytes32 s) = vm.sign(1, hash); 12 | address signer = ecrecover(hash, v, r, s); 13 | assertEq(alice, signer); 14 | } 15 | 16 | function testSign_symbolic(uint256 pk) public { 17 | vm.assume(pk != 0); 18 | vm.assume(pk < 115792089237316195423570985008687907852837564279074904382605163141518161494337); 19 | address fromPk = vm.addr(pk); 20 | bytes32 hash = keccak256("Signed by private key"); 21 | (uint8 v, bytes32 r, bytes32 s) = vm.sign(pk, hash); 22 | address signer = ecrecover(hash, v, r, s); 23 | assertEq(fromPk, signer); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/Simple.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | import "kontrol-cheatcodes/KontrolCheats.sol"; 6 | 7 | contract AssertTest is Test, KontrolCheats { 8 | uint y; 9 | 10 | function call_assert_false() public pure { 11 | assert(false); 12 | } 13 | 14 | function setUp() public {} 15 | 16 | function test_failing_branch(uint x) public { 17 | assert(x >= 100); 18 | } 19 | 20 | function test_assert_true() public pure { 21 | assert(true); 22 | } 23 | 24 | function prove_assert_true() public pure { 25 | assert(true); 26 | } 27 | 28 | function test_assert_true_branch(uint x) public { 29 | if (x < 3) { 30 | y = x; 31 | assert(true); 32 | } else { 33 | y = x - 1; 34 | assert(true); 35 | } 36 | assert(y <= x); 37 | } 38 | 39 | function test_assert_false() public pure { 40 | assert(false); 41 | } 42 | 43 | function testFail_assert_true() public pure { 44 | assert(true); 45 | } 46 | 47 | function checkFail_assert_false() public pure { 48 | assert(false); 49 | } 50 | 51 | function testFail_expect_revert() public { 52 | vm.expectRevert(); 53 | this.call_assert_false(); 54 | } 55 | 56 | function test_revert_branch(uint x, uint y) public{ 57 | if (x < y) { 58 | assert(true); 59 | } else { 60 | assert(false); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/SnapshotTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | struct Storage { 7 | uint slot0; 8 | uint slot1; 9 | } 10 | 11 | contract SnapshotTest is Test { 12 | Storage store; 13 | 14 | function setUp() public { 15 | store.slot0 = 10; 16 | store.slot1 = 20; 17 | } 18 | 19 | function testSnapshot() public { 20 | uint256 snapshot = vm.snapshot(); 21 | store.slot0 = 300; 22 | store.slot1 = 400; 23 | 24 | assertEq(store.slot0, 300); 25 | assertEq(store.slot1, 400); 26 | 27 | // after resetting to a snapshot all changes are discarded 28 | vm.revertTo(snapshot); 29 | assertEq(store.slot0, 10, "snapshot revert for slot 0 unsuccessful"); 30 | assertEq(store.slot1, 20, "snapshot revert for slot 1 unsuccessful"); 31 | } 32 | 33 | } 34 | 35 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/SymbolicStorageTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | import "kontrol-cheatcodes/KontrolCheats.sol"; 6 | 7 | contract SymbolicStore { 8 | uint256 private testNumber = 1337; // slot 0 9 | constructor() {} 10 | } 11 | 12 | contract SymbolicStorageTest is Test, KontrolCheats { 13 | function testFail_SymbolicStorage(uint256 slot) public { 14 | address addr = 0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8; 15 | kevm.symbolicStorage(addr); 16 | bytes32 value = vm.load(addr, bytes32(slot)); 17 | require(value != 0); 18 | assertEq(uint256(value), 0); 19 | } 20 | 21 | function testFail_SymbolicStorage1(uint256 slot) public { 22 | SymbolicStore myStore = new SymbolicStore(); 23 | kevm.symbolicStorage(address(myStore)); 24 | bytes32 value = vm.load(address(myStore), bytes32(uint256(slot))); 25 | require(value != 0); 26 | assertEq(uint256(value), 0); 27 | } 28 | 29 | function testEmptyInitialStorage(uint256 slot) public { 30 | bytes32 storage_value = vm.load(address(vm), bytes32(slot)); 31 | assertEq(uint256(storage_value), 0); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/ToStringTest.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | contract ToStringTest is Test { 7 | 8 | function testAddressToString() public { 9 | address addr = 0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8; 10 | string memory addrStr = vm.toString(addr); 11 | assertEq("0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8", addrStr); 12 | } 13 | 14 | function testBytesToString() public { 15 | bytes memory bts = hex"7109709ecfa91a80626ff3989d68f67f5b1dd12d"; 16 | string memory btsStr = vm.toString(bts); 17 | assertEq("0x7109709ecfa91a80626ff3989d68f67f5b1dd12d", btsStr); 18 | } 19 | 20 | function testBytes32ToString() public { 21 | bytes32 bts = 0x00; 22 | string memory btsStr = vm.toString(bts); 23 | assertEq("0x0000000000000000000000000000000000000000000000000000000000000000", btsStr); 24 | } 25 | 26 | function testBoolToString() public { 27 | string memory boolStr = vm.toString(true); 28 | assertEq("true", boolStr); 29 | boolStr = vm.toString(false); 30 | assertEq("false", boolStr); 31 | } 32 | 33 | function testUint256ToString() public { 34 | uint256 number = 1234; 35 | string memory numberStr = vm.toString(number); 36 | assertEq("1234", numberStr); 37 | } 38 | 39 | function testIntToString() public { 40 | int number = -1234; 41 | string memory numberStr = vm.toString(number); 42 | assertEq("-1234", numberStr); 43 | } 44 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/file.txt: -------------------------------------------------------------------------------- 1 | This is a file 2 | for testing 3 | file manipulation functions. 4 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/myscript.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo -n $FOO 3 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/nested/SimpleNested.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | import "kontrol-cheatcodes/KontrolCheats.sol"; 6 | 7 | contract AssertNestedTest is Test, KontrolCheats { 8 | function test_assert_true_nested() public pure { 9 | assert(true); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/foundry/test/script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ $FOO ] 3 | # true encoded 4 | then echo -n 0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000047472756500000000000000000000000000000000000000000000000000000000 5 | # false encoded 6 | else echo -n 0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000566616c7365000000000000000000000000000000000000000000000000000000 7 | fi 8 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/show/foundry.k.expected: -------------------------------------------------------------------------------- 1 | requires "kontrol.md" 2 | requires "requires/lemmas.k" 3 | requires "requires/cse-lemmas.k" 4 | requires "requires/pausability-lemmas.k" 5 | requires "requires/symbolic-bytes-lemmas.k" 6 | 7 | module KONTROL-MAIN 8 | imports public CSE-LEMMAS 9 | imports public SYMBOLIC-BYTES-LEMMAS 10 | imports public SUM-TO-N-INVARIANT 11 | imports public PAUSABILITY-LEMMAS 12 | imports public KONTROL-KECCAK 13 | 14 | 15 | 16 | endmodule 17 | -------------------------------------------------------------------------------- /src/tests/integration/test-data/src/AllowCalls.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | import "kontrol-cheatcodes/KontrolCheats.sol"; 6 | 7 | contract ValueStore { 8 | uint256 public slot0; 9 | uint256 public slot1; 10 | 11 | function changeSlot0(uint256 newValue) public { 12 | slot0 = newValue; 13 | } 14 | 15 | function changeSlot1(uint256 newValue) public { 16 | slot1 = newValue; 17 | } 18 | } 19 | 20 | contract AllowChangesTest is Test, KontrolCheats { 21 | ValueStore canChange; 22 | ValueStore cannotChange; 23 | 24 | function setUp() public { 25 | canChange = new ValueStore(); 26 | cannotChange = new ValueStore(); 27 | } 28 | 29 | function testAllowCalls(uint256 value) public { 30 | /* Whitelisting two calls to ensure that `allowCalls` is working 31 | for whitelist with > 1 elements */ 32 | bytes memory changeCallDataOne = abi.encodeWithSelector( 33 | ValueStore.changeSlot0.selector, 34 | value 35 | ); 36 | 37 | bytes memory changeCallDataTwo = abi.encodeWithSelector( 38 | ValueStore.changeSlot1.selector, 39 | value 40 | ); 41 | 42 | kevm.allowCalls(address(canChange), changeCallDataOne); 43 | kevm.allowCalls(address(canChange), changeCallDataTwo); 44 | 45 | canChange.changeSlot0(value); 46 | } 47 | 48 | function testFailAllowCalls_ifNotWhitelisted(uint256 value) public { 49 | bytes memory changeCallData = abi.encodeWithSelector( 50 | ValueStore.changeSlot0.selector, 51 | value 52 | ); 53 | 54 | kevm.allowCalls(address(canChange), changeCallData); 55 | 56 | canChange.changeSlot1(value); 57 | } 58 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/src/ForgetBranch.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity >=0.8.13; 3 | 4 | import {Test, console} from "forge-std/Test.sol"; 5 | import "kontrol-cheatcodes/KontrolCheats.sol"; 6 | 7 | 8 | contract ForgetBranchTest is Test, KontrolCheats { 9 | 10 | function test_forgetBranch(uint256 x) public { 11 | uint256 y; 12 | 13 | vm.assume(x > 200); 14 | kevm.forgetBranch(x, KontrolCheatsBase.ComparisonOperator.GreaterThan, 200); 15 | if(x > 200){ 16 | y = 21; 17 | } else { 18 | y = 42; 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/src/RandomVar.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.13; 3 | 4 | import {Test, console} from "forge-std/Test.sol"; 5 | import "kontrol-cheatcodes/KontrolCheats.sol"; 6 | 7 | contract RandomVarTest is Test, KontrolCheats { 8 | uint256 constant length_limit = 72; 9 | 10 | function test_randomBool() public view { 11 | bool freshBool = vm.randomBool(); 12 | vm.assume(freshBool); 13 | } 14 | 15 | function test_randomAddress() public { 16 | address freshAddress = vm.randomAddress(); 17 | assertNotEq(freshAddress, address(this)); 18 | assertNotEq(freshAddress, address(vm)); 19 | } 20 | 21 | function test_randomBytes_length(uint256 len) public view { 22 | vm.assume(0 < len); 23 | vm.assume(len <= length_limit); 24 | bytes memory freshBytes = vm.randomBytes(len); 25 | assertEq(freshBytes.length, len); 26 | } 27 | 28 | function test_randomBytes4_length() public view { 29 | bytes4 freshBytes = vm.randomBytes4(); 30 | assertEq(freshBytes.length, 4); 31 | } 32 | 33 | function test_randomBytes8_length() public view { 34 | bytes8 freshBytes = vm.randomBytes8(); 35 | assertEq(freshBytes.length, 8); 36 | } 37 | 38 | function test_randomUint_192() public { 39 | uint256 randomUint192 = vm.randomUint(192); 40 | 41 | assert(0 <= randomUint192); 42 | assert(randomUint192 <= type(uint192).max); 43 | } 44 | 45 | function test_randomUint_Range(uint256 min, uint256 max) public { 46 | vm.assume(max >= min); 47 | uint256 rand = vm.randomUint(min, max); 48 | assertTrue(rand >= min, "rand >= min"); 49 | assertTrue(rand <= max, "rand <= max"); 50 | } 51 | 52 | function test_randomUint() public { 53 | uint256 rand = vm.randomUint(); 54 | assertTrue(rand >= type(uint256).min); 55 | assertTrue(rand <= type(uint256).max); 56 | } 57 | function test_custom_names() public { 58 | bool x = kevm.freshBool("BOOLEAN"); 59 | bool y = kevm.freshBool("BOOLEAN"); 60 | vm.assume(x == true); 61 | vm.assume(y == false); 62 | uint256 slot = freshUInt256("NEW_SLOT"); 63 | address new_account = kevm.freshAddress("NEW_ACCOUNT"); 64 | kevm.symbolicStorage(new_account, "NEW_ACCOUNT_STORAGE"); 65 | bytes memory value = kevm.freshBytes(32, "NEW_BYTES"); 66 | vm.store(new_account, bytes32(slot), bytes32(value)); 67 | } 68 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/src/TransientStorage.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.25; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | contract TransientStorageTest is Test { 7 | function testTransientStoreLoad(uint256 key, uint256 value) public { 8 | // Store `value` at `key` in transient storage 9 | assembly { 10 | tstore(key, value) 11 | } 12 | 13 | uint256 loadedValue; 14 | 15 | // Load `value` from `key` in transient storage 16 | assembly { 17 | loadedValue := tload(key) 18 | } 19 | 20 | assertEq(loadedValue, value, "TLOAD did not return the correct value"); 21 | } 22 | } -------------------------------------------------------------------------------- /src/tests/integration/test-data/xor-lemmas.k: -------------------------------------------------------------------------------- 1 | module XOR-LEMMAS 2 | imports KONTROL-MAIN 3 | 4 | rule A xorInt A => 0 [simplification] 5 | 6 | endmodule 7 | -------------------------------------------------------------------------------- /src/tests/integration/test_hevm_prove.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import sys 4 | from typing import TYPE_CHECKING 5 | 6 | import pytest 7 | from pyk.utils import single 8 | 9 | from kontrol.options import ProveOptions 10 | from kontrol.prove import foundry_prove 11 | 12 | from .utils import assert_fail, assert_pass 13 | 14 | if TYPE_CHECKING: 15 | from typing import Final 16 | 17 | from pyk.kore.rpc import KoreServer 18 | from pyk.utils import BugReport 19 | 20 | from kontrol.foundry import Foundry 21 | 22 | 23 | sys.setrecursionlimit(10**7) 24 | 25 | ALL_HEVM_TESTS_PASSING: Final = ( 26 | 'HevmTests.prove_require_assert_true', 27 | 'HevmTests.proveFail_require_assert', 28 | 'HevmTests.prove_revert', 29 | ) 30 | 31 | 32 | @pytest.mark.parametrize('test', ALL_HEVM_TESTS_PASSING) 33 | def test_hevm_prove_passing( 34 | test: str, 35 | foundry: Foundry, 36 | bug_report: BugReport | None, 37 | server: KoreServer, 38 | no_use_booster: bool, 39 | force_sequential: bool, 40 | ) -> None: 41 | if no_use_booster: 42 | pytest.skip() 43 | 44 | if bug_report is not None: 45 | server._populate_bug_report(bug_report) 46 | 47 | prove_res = foundry_prove( 48 | foundry=foundry, 49 | options=ProveOptions( 50 | { 51 | 'counterexample_info': True, 52 | 'bug_report': bug_report, 53 | 'hevm': True, 54 | 'port': server.port, 55 | 'tests': [(test, None)], 56 | 'force_sequential': force_sequential, 57 | } 58 | ), 59 | ) 60 | 61 | assert_pass(test, single(prove_res)) 62 | 63 | 64 | ALL_HEVM_TESTS_FAILING: Final = ( 65 | 'HevmTests.prove_require_assert_false', 66 | 'HevmTests.proveFail_all_branches', 67 | ) 68 | 69 | 70 | @pytest.mark.parametrize('test', ALL_HEVM_TESTS_FAILING) 71 | def test_hevm_prove_failing( 72 | test: str, 73 | foundry: Foundry, 74 | bug_report: BugReport | None, 75 | server: KoreServer, 76 | no_use_booster: bool, 77 | force_sequential: bool, 78 | ) -> None: 79 | if no_use_booster: 80 | pytest.skip() 81 | 82 | if bug_report is not None: 83 | server._populate_bug_report(bug_report) 84 | 85 | prove_res = foundry_prove( 86 | foundry=foundry, 87 | options=ProveOptions( 88 | { 89 | 'tests': [(test, None)], 90 | 'counterexample_info': True, 91 | 'bug_report': bug_report, 92 | 'hevm': True, 93 | 'port': server.port, 94 | 'force_sequential': force_sequential, 95 | } 96 | ), 97 | ) 98 | 99 | assert_fail(test, single(prove_res)) 100 | -------------------------------------------------------------------------------- /src/tests/integration/test_kontrol_cse.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import sys 4 | from typing import TYPE_CHECKING 5 | 6 | import pytest 7 | 8 | from kontrol.display import foundry_show 9 | from kontrol.options import ProveOptions, ShowOptions 10 | from kontrol.prove import ConfigType, foundry_prove 11 | 12 | from .utils import TEST_DATA_DIR, assert_or_update_show_output 13 | 14 | if TYPE_CHECKING: 15 | from typing import Final 16 | 17 | from pyk.kore.rpc import KoreServer 18 | from pyk.utils import BugReport 19 | 20 | from kontrol.foundry import Foundry 21 | 22 | 23 | sys.setrecursionlimit(10**7) 24 | 25 | 26 | ALL_DEPENDENCY_TESTS: Final = tuple((TEST_DATA_DIR / 'foundry-dependency-all').read_text().splitlines()) 27 | SKIPPED_DEPENDENCY_TESTS: Final = set((TEST_DATA_DIR / 'foundry-dependency-skip').read_text().splitlines()) 28 | 29 | 30 | @pytest.mark.parametrize('test_id', ALL_DEPENDENCY_TESTS) 31 | def test_foundry_dependency_automated( 32 | test_id: str, 33 | foundry: Foundry, 34 | bug_report: BugReport | None, 35 | server: KoreServer, 36 | update_expected_output: bool, 37 | no_use_booster: bool, 38 | force_sequential: bool, 39 | ) -> None: 40 | if no_use_booster: 41 | pytest.skip() 42 | 43 | test_contract_name = test_id.split('.')[0] 44 | config_type = ConfigType.TEST_CONFIG if test_contract_name.endswith('Test') else ConfigType.SUMMARY_CONFIG 45 | 46 | if test_id in SKIPPED_DEPENDENCY_TESTS: 47 | pytest.skip() 48 | 49 | if bug_report is not None: 50 | server._populate_bug_report(bug_report) 51 | 52 | run_constructor = True 53 | if test_id in ['CallableStorageTest.test_str()', 'CallableStorageContract.str()']: 54 | run_constructor = False 55 | 56 | foundry_prove( 57 | foundry=foundry, 58 | options=ProveOptions( 59 | { 60 | 'max_depth': 10000, 61 | 'max_iterations': 100, 62 | 'bug_report': bug_report, 63 | 'cse': True, 64 | 'minimize_proofs': True, 65 | 'fail_fast': False, 66 | 'workers': 2, 67 | 'port': server.port, 68 | 'tests': [(test_id, None)], 69 | 'config_type': config_type, 70 | 'run_constructor': run_constructor, 71 | 'force_sequential': force_sequential, 72 | 'enum_constraints': True, 73 | } 74 | ), 75 | ) 76 | 77 | cse_show_res = foundry_show( 78 | foundry=foundry, 79 | options=ShowOptions( 80 | { 81 | 'test': test_id, 82 | 'to_module': True, 83 | 'sort_collections': True, 84 | 'omit_unstable_output': True, 85 | 'pending': False, 86 | 'failing': False, 87 | 'failure_info': False, 88 | 'counterexample_info': False, 89 | 'port': server.port, 90 | } 91 | ), 92 | ) 93 | 94 | assert_or_update_show_output( 95 | cse_show_res, TEST_DATA_DIR / f'show/{test_id}.cse.expected', update=update_expected_output 96 | ) 97 | -------------------------------------------------------------------------------- /src/tests/integration/utils.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from difflib import unified_diff 4 | from pathlib import Path 5 | from typing import TYPE_CHECKING 6 | 7 | import pytest 8 | from pyk.proof import APRProof 9 | from pyk.proof.reachability import APRFailureInfo 10 | 11 | if TYPE_CHECKING: 12 | from typing import Final 13 | 14 | from pyk.proof.proof import Proof 15 | 16 | 17 | TEST_DATA_DIR: Final = (Path(__file__).parent / 'test-data').resolve(strict=True) 18 | 19 | 20 | def assert_or_update_show_output(actual_text: str, expected_file: Path, *, update: bool) -> None: 21 | if update: 22 | expected_file.write_text(actual_text) 23 | else: 24 | assert expected_file.is_file() 25 | expected_text = expected_file.read_text() 26 | if actual_text != expected_text: 27 | diff = '\n'.join( 28 | unified_diff( 29 | expected_text.splitlines(), 30 | actual_text.splitlines(), 31 | fromfile=str(expected_file), 32 | tofile='actual_text', 33 | lineterm='', 34 | ) 35 | ) 36 | raise AssertionError(f'The actual output does not match the expected output:\n{diff}') 37 | 38 | 39 | def assert_pass(test: str, proof: Proof) -> None: 40 | if not proof.passed: 41 | if isinstance(proof, APRProof): 42 | assert proof.failure_info 43 | assert isinstance(proof.failure_info, APRFailureInfo) 44 | pytest.fail('\n'.join(proof.failure_info.print())) 45 | else: 46 | pytest.fail() 47 | 48 | 49 | def assert_fail(test: str, proof: Proof) -> None: 50 | assert not proof.passed 51 | if isinstance(proof, APRProof): 52 | assert proof.failure_info 53 | -------------------------------------------------------------------------------- /src/tests/profiling/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runtimeverification/kontrol/28d44863fbae232e3ab1e6677fda3af843917150/src/tests/profiling/__init__.py -------------------------------------------------------------------------------- /src/tests/profiling/test-data/foundry/foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | src = 'src' 3 | out = 'out' 4 | extra_output = ['storageLayout', 'abi', 'evm.methodIdentifiers', 'evm.deployedBytecode.object'] 5 | -------------------------------------------------------------------------------- /src/tests/profiling/test-data/foundry/test/Simple.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity =0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | contract AssertTest is Test { 7 | 8 | function test_revert_branch(uint x, uint y) public{ 9 | if (x < y) { 10 | assert(true); 11 | } else { 12 | assert(false); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/tests/profiling/test_foundry_prove.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import sys 4 | from typing import TYPE_CHECKING 5 | 6 | from kontrol.kompile import foundry_kompile 7 | from kontrol.options import BuildOptions, ProveOptions 8 | from kontrol.prove import foundry_prove 9 | 10 | from ..utils import forge_build 11 | from .utils import TEST_DATA_DIR 12 | 13 | if TYPE_CHECKING: 14 | from pathlib import Path 15 | 16 | from pyk.testing import Profiler 17 | from pyk.utils import BugReport 18 | 19 | 20 | sys.setrecursionlimit(10**7) 21 | 22 | 23 | def test_foundy_prove( 24 | profile: Profiler, no_use_booster: bool, bug_report: BugReport | None, tmp_path: Path, force_sequential: bool 25 | ) -> None: 26 | foundry_root = tmp_path / 'foundry' 27 | foundry = forge_build(TEST_DATA_DIR, foundry_root) 28 | 29 | with profile('kompile.prof', sort_keys=('cumtime', 'tottime'), limit=15): 30 | foundry_kompile( 31 | BuildOptions( 32 | {'includes': (), 'metadata': False}, 33 | ), 34 | foundry=foundry, 35 | ) 36 | 37 | with profile('prove.prof', sort_keys=('cumtime', 'tottime'), limit=100): 38 | foundry_prove( 39 | options=ProveOptions( 40 | { 41 | 'bug_report': bug_report, 42 | 'use_booster': not no_use_booster, 43 | 'tests': [('AssertTest.test_revert_branch', None)], 44 | 'force_sequential': force_sequential, 45 | } 46 | ), 47 | foundry=foundry, 48 | ) 49 | -------------------------------------------------------------------------------- /src/tests/profiling/utils.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from pathlib import Path 4 | from typing import TYPE_CHECKING 5 | 6 | if TYPE_CHECKING: 7 | from typing import Final 8 | 9 | 10 | TEST_DATA_DIR: Final = (Path(__file__).parent / 'test-data').resolve(strict=True) 11 | -------------------------------------------------------------------------------- /src/tests/unit/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runtimeverification/kontrol/28d44863fbae232e3ab1e6677fda3af843917150/src/tests/unit/__init__.py -------------------------------------------------------------------------------- /src/tests/unit/test-data/accesses.json: -------------------------------------------------------------------------------- 1 | { 2 | "accountAccesses": [{"accessor":"0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496","account":"0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f","chainInfo":{"chainId":31337,"forkId":0},"data":"0x608060405234801561001057600080fd5b50610106806100206000396000f3fe6080604052348015600f57600080fd5b5060043610603c5760003560e01c80633fb5c1cb1460415780638381f58a146053578063d09de08a14606d575b600080fd5b6051604c3660046083565b600055565b005b605b60005481565b60405190815260200160405180910390f35b6051600080549080607c83609b565b9190505550565b600060208284031215609457600080fd5b5035919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820360f2577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b506001019056fea164736f6c634300080f000a","deployedCode":"0x6080604052348015600f57600080fd5b5060043610603c5760003560e01c80633fb5c1cb1460415780638381f58a146053578063d09de08a14606d575b600080fd5b6051604c3660046083565b600055565b005b605b60005481565b60405190815260200160405180910390f35b6051600080549080607c83609b565b9190505550565b600060208284031215609457600080fd5b5035919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820360f2577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b506001019056fea164736f6c634300080f000a","initialized":true,"kind":"Create","newBalance":0,"oldBalance":0,"reverted":false,"storageAccesses":[],"value":0},{"accessor":"0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496","account":"0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f","chainInfo":{"chainId":31337,"forkId":0},"data":"0x3fb5c1cb0000000000000000000000000000000000000000000000000000000000000003","deployedCode":"0x","initialized":true,"kind":"Call","newBalance":0,"oldBalance":0,"reverted":false,"storageAccesses": [{"account":"0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f","isWrite":true,"newValue":"0x0000000000000000000000000000000000000000000000000000000000000003","previousValue":"0x0000000000000000000000000000000000000000000000000000000000000000","reverted":false,"slot":"0x0000000000000000000000000000000000000000000000000000000000000000"}],"value":0}] 3 | } 4 | -------------------------------------------------------------------------------- /src/tests/unit/test-data/foundry-list/apr_proofs/test%AssertTest.checkFail_assert_false():0/proof.json: -------------------------------------------------------------------------------- 1 | {"id": "test%AssertTest.checkFail_assert_false():0", "subproof_ids": [], "admitted": false, "type": "APRProof", "init": 1, "target": 5, "terminal": [3, 5, 6], "node_refutations": {}, "circularity": false, "logs": {"6": []}, "bounded": []} 2 | -------------------------------------------------------------------------------- /src/tests/unit/test-data/foundry-list/apr_proofs/test%AssertTest.setUp():0/proof.json: -------------------------------------------------------------------------------- 1 | {"id": "test%AssertTest.setUp():0", "subproof_ids": [], "admitted": false, "type": "APRProof", "init": 1, "target": 2, "terminal": [2, 3], "node_refutations": {}, "circularity": false, "logs": {"3": []}, "bounded": []} 2 | -------------------------------------------------------------------------------- /src/tests/unit/test-data/foundry-list/apr_proofs/test%AssertTest.testFail_assert_true():0/kcfg/kcfg.json: -------------------------------------------------------------------------------- 1 | {"next": 7, "nodes": [1, 3, 4, 5, 6], "edges": [{"source": 1, "target": 3, "depth": 182, "rules": []}, {"source": 3, "target": 4, "depth": 1, "rules": []}, {"source": 4, "target": 6, "depth": 203, "rules": []}], "covers": [], "splits": [], "ndbranches": [], "vacuous": [], "stuck": [], "aliases": {}} -------------------------------------------------------------------------------- /src/tests/unit/test-data/foundry-list/apr_proofs/test%AssertTest.testFail_assert_true():0/proof.json: -------------------------------------------------------------------------------- 1 | {"id": "test%AssertTest.testFail_assert_true():0", "subproof_ids": [], "admitted": false, "type": "APRProof", "init": 1, "target": 5, "terminal": [3, 5, 6], "node_refutations": {}, "circularity": false, "logs": {"6": []}, "bounded": []} 2 | -------------------------------------------------------------------------------- /src/tests/unit/test-data/foundry-list/apr_proofs/test%AssertTest.test_assert_false():0/kcfg/kcfg.json: -------------------------------------------------------------------------------- 1 | {"next": 7, "nodes": [1, 3, 4, 5, 6], "edges": [{"source": 1, "target": 3, "depth": 182, "rules": []}, {"source": 3, "target": 4, "depth": 1, "rules": []}, {"source": 4, "target": 6, "depth": 310, "rules": []}], "covers": [], "splits": [], "ndbranches": [], "vacuous": [], "stuck": [], "aliases": {}} -------------------------------------------------------------------------------- /src/tests/unit/test-data/foundry-list/apr_proofs/test%AssertTest.test_assert_false():0/proof.json: -------------------------------------------------------------------------------- 1 | {"id": "test%AssertTest.test_assert_false():0", "subproof_ids": [], "admitted": false, "type": "APRProof", "init": 1, "target": 5, "terminal": [3, 5, 6], "node_refutations": {}, "circularity": false, "logs": {"6": []}, "bounded": []} 2 | -------------------------------------------------------------------------------- /src/tests/unit/test-data/foundry-list/apr_proofs/test%AssertTest.test_assert_true():0/proof.json: -------------------------------------------------------------------------------- 1 | {"id": "test%AssertTest.test_assert_true():0", "subproof_ids": [], "admitted": false, "type": "APRProof", "init": 1, "target": 5, "terminal": [3, 5, 6], "node_refutations": {}, "circularity": false, "logs": {"6": []}, "bounded": []} 2 | -------------------------------------------------------------------------------- /src/tests/unit/test-data/foundry-list/foundry-list.expected: -------------------------------------------------------------------------------- 1 | APRProof: test%AssertTest.checkFail_assert_false():0 2 | status: ProofStatus.PASSED 3 | admitted: False 4 | nodes: 5 5 | pending: 0 6 | failing: 0 7 | vacuous: 0 8 | stuck: 0 9 | terminal: 3 10 | refuted: 0 11 | bounded: 0 12 | execution time: 0s 13 | Subproofs: 0 14 | 15 | APRProof: test%AssertTest.setUp():0 16 | status: ProofStatus.PASSED 17 | admitted: False 18 | nodes: 3 19 | pending: 0 20 | failing: 0 21 | vacuous: 0 22 | stuck: 0 23 | terminal: 2 24 | refuted: 0 25 | bounded: 0 26 | execution time: 0s 27 | Subproofs: 0 28 | 29 | APRProof: test%AssertTest.testFail_assert_true():0 30 | status: ProofStatus.FAILED 31 | admitted: False 32 | nodes: 5 33 | pending: 0 34 | failing: 1 35 | vacuous: 0 36 | stuck: 0 37 | terminal: 3 38 | refuted: 0 39 | bounded: 0 40 | execution time: 0s 41 | Subproofs: 0 42 | 43 | APRProof: test%AssertTest.test_assert_false():0 44 | status: ProofStatus.FAILED 45 | admitted: False 46 | nodes: 5 47 | pending: 0 48 | failing: 1 49 | vacuous: 0 50 | stuck: 0 51 | terminal: 3 52 | refuted: 0 53 | bounded: 0 54 | execution time: 0s 55 | Subproofs: 0 56 | 57 | APRProof: test%AssertTest.test_assert_true():0 58 | status: ProofStatus.PASSED 59 | admitted: False 60 | nodes: 5 61 | pending: 0 62 | failing: 0 63 | vacuous: 0 64 | stuck: 0 65 | terminal: 3 66 | refuted: 0 67 | bounded: 0 68 | execution time: 0s 69 | Subproofs: 0 -------------------------------------------------------------------------------- /src/tests/unit/test-data/kontrol_test.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | verbose = false 3 | debug = false 4 | foundry-project-root = '.' 5 | 6 | [build.a_profile] 7 | verbose = false 8 | debug = false 9 | optimization-level = 3 10 | require = 'xor-lemmas.k' 11 | module-import = 'TestBase:XOR-LEMMAS' 12 | 13 | [prove.b_profile] 14 | verbose = true 15 | debug = true 16 | workers = 5 17 | smt-timeout = 1000 18 | 19 | [show.default] 20 | version = 3 21 | verbose = true 22 | debug = true 23 | node-delta = '10,#target' 24 | -------------------------------------------------------------------------------- /src/tests/unit/test_foundry_list.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from functools import cached_property 4 | from os import listdir 5 | from typing import TYPE_CHECKING, cast 6 | 7 | import pytest 8 | from pyk.proof.proof import Proof 9 | 10 | from kontrol.foundry import Foundry, foundry_list 11 | from kontrol.solc_to_k import Contract 12 | 13 | from .utils import TEST_DATA_DIR 14 | 15 | if TYPE_CHECKING: 16 | from pathlib import Path 17 | from typing import Final 18 | 19 | 20 | LIST_DATA_DIR: Final = TEST_DATA_DIR / 'foundry-list' 21 | LIST_APR_PROOF: Final = LIST_DATA_DIR / 'apr_proofs' 22 | LIST_EXPECTED: Final = LIST_DATA_DIR / 'foundry-list.expected' 23 | 24 | 25 | class FoundryMock: 26 | @property 27 | def proofs_dir(self) -> Path: 28 | return LIST_DATA_DIR / 'apr_proofs' 29 | 30 | @cached_property 31 | def contracts(self) -> dict[str, Contract]: 32 | ret: dict[str, Contract] = {} 33 | for full_method in listdir(LIST_APR_PROOF): 34 | contract = Contract.__new__(Contract) 35 | method = Contract.Method.__new__(Contract.Method) 36 | contract_method, *_ = full_method.split(':') 37 | contract._name, method.signature = contract_method.split('.') 38 | contract.contract_path = contract._name 39 | if not hasattr(contract, 'methods'): 40 | contract.methods = () 41 | contract.methods = contract.methods + (method,) 42 | ret[full_method] = contract 43 | return ret 44 | 45 | def get_optional_proof(self, test_id: str) -> Proof | None: 46 | return Proof.read_proof_data(LIST_APR_PROOF, test_id) 47 | 48 | 49 | def test_foundry_list(update_expected_output: bool) -> None: 50 | # Given 51 | foundry = cast('Foundry', FoundryMock()) 52 | expected = LIST_EXPECTED.read_text() 53 | 54 | # When 55 | actual = '\n'.join(foundry_list(foundry)) 56 | 57 | # Then 58 | if update_expected_output: 59 | LIST_EXPECTED.write_text(actual) 60 | return 61 | 62 | assert actual == expected 63 | 64 | 65 | PROOF_ID_DATA: list[tuple[str, str, list[str], list[str]]] = [ 66 | ( 67 | 'common_case', 68 | 'AssertTest.setUp', 69 | [ 70 | 'test%AssertTest.setUp():0', 71 | 'test_1%test_2%ContractName.functionName(uint256):1', 72 | 'test_1%ContractName:functionName():0', 73 | ], 74 | ['test%AssertTest.setUp():0'], 75 | ), 76 | ( 77 | 'nested_case', 78 | 'functionName', 79 | [ 80 | 'test%AssertTest.setUp():0', 81 | 'test_1%test_2%ContractName.functionName(uint256):1', 82 | 'test_1%ContractName:functionName():0', 83 | 'OtherContract.functionName(string):0', 84 | ], 85 | ['test_1%test_2%ContractName.functionName(uint256):1'], 86 | ), 87 | ] 88 | 89 | 90 | @pytest.mark.parametrize( 91 | 'test_id,test_name,proof_ids,expected', PROOF_ID_DATA, ids=[test_id for test_id, *_ in PROOF_ID_DATA] 92 | ) 93 | def test_proof_identification(test_id: str, test_name: str, proof_ids: list[str], expected: list[str]) -> None: 94 | # When 95 | actual = Foundry.filter_proof_ids(proof_ids, test_name) 96 | 97 | # Then 98 | assert actual == expected 99 | -------------------------------------------------------------------------------- /src/tests/unit/test_get_test_id.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | import pytest 6 | 7 | from kontrol.foundry import Foundry 8 | 9 | if TYPE_CHECKING: 10 | pass 11 | 12 | from _pytest.monkeypatch import MonkeyPatch # Importing the type for annotation 13 | 14 | 15 | def mock_listdir(_f: Foundry) -> list[str]: 16 | return [ 17 | 'test%AssertTest.checkFail_assert_false():0', 18 | 'test%AssertTest.test_assert_false():0', 19 | 'test%AssertTest.test_assert_true():0', 20 | 'test%AssertTest.testFail_assert_true():0', 21 | 'test%AssertTest.setUp():0', 22 | 'test%AssertTest.setUp():1', 23 | ] 24 | 25 | 26 | def mock_all_tests() -> list[str]: 27 | return [ 28 | 'test%AssertTest.checkFail_assert_false()', 29 | 'test%AssertTest.test_assert_false()', 30 | 'test%AssertTest.test_assert_true()', 31 | 'test%AssertTest.testFail_assert_true()', 32 | ] 33 | 34 | 35 | def mock_all_non_tests() -> list[str]: 36 | return ['test%AssertTest.setUp()'] 37 | 38 | 39 | TEST_ID_DATA: list[tuple[str, str, int | None, bool, str]] = [ 40 | ( 41 | 'with_version', 42 | 'AssertTest.setUp()', 43 | 0, 44 | False, 45 | 'test%AssertTest.setUp():0', 46 | ), 47 | ( 48 | 'without_version', 49 | 'AssertTest.setUp()', 50 | None, 51 | False, 52 | 'test%AssertTest.setUp():1', 53 | ), 54 | ( 55 | 'no_matches', 56 | 'AssertTest.setUp()', 57 | 3, 58 | True, 59 | r'Found no matching proofs for AssertTest\.setUp\(\):3\.', 60 | ), 61 | ( 62 | 'multiple_matches_with_version', 63 | 'AssertTest.test_assert', 64 | 0, 65 | True, 66 | r'Found 2 matching proofs for AssertTest\.test_assert:0\.', 67 | ), 68 | ( 69 | 'multiple_matches_without_version', 70 | 'AssertTest.test_assert', 71 | None, 72 | True, 73 | r'Found 2 matching proofs for AssertTest\.test_assert:None\.', 74 | ), 75 | ] 76 | 77 | 78 | @pytest.mark.parametrize( 79 | 'test_id,test,version,expect_error,expected_str', TEST_ID_DATA, ids=[test_id for test_id, *_ in TEST_ID_DATA] 80 | ) 81 | def test_foundry_get_test_id( 82 | monkeypatch: MonkeyPatch, test_id: str, test: str, version: int | None, expect_error: bool, expected_str: str 83 | ) -> None: 84 | # Given 85 | monkeypatch.setattr(Foundry, '__init__', lambda _: None) 86 | monkeypatch.setattr(Foundry, 'list_proof_dir', mock_listdir) 87 | monkeypatch.setattr(Foundry, 'all_tests', mock_all_tests()) 88 | monkeypatch.setattr(Foundry, 'all_non_tests', mock_all_non_tests()) 89 | monkeypatch.setattr(Foundry, 'resolve_proof_version', lambda _self, _test, _reinit, _version: 1) 90 | 91 | foundry = Foundry() # type: ignore 92 | 93 | if expect_error: 94 | # When/Then 95 | with pytest.raises(ValueError, match=expected_str): 96 | foundry.get_test_id(test, version) 97 | else: 98 | # When 99 | id = foundry.get_test_id(test, version) 100 | 101 | # Then 102 | assert id == expected_str 103 | -------------------------------------------------------------------------------- /src/tests/unit/test_latest_proof_version.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | import pytest 6 | 7 | from kontrol.foundry import Foundry 8 | 9 | if TYPE_CHECKING: 10 | pass 11 | 12 | from _pytest.monkeypatch import MonkeyPatch # Importing the type for annotation 13 | 14 | 15 | def mock_listdir(_f: Foundry) -> list[str]: 16 | return [ 17 | 'test%AssertTest.test_assert_true():0', 18 | 'test%AssertTest.setUp():0', 19 | 'test%AssertTest.setUp():1', 20 | 'long%path%to%test%DeeplyNestedTest.testWithMultipleVersions():0', 21 | 'long%path%to%test%DeeplyNestedTest.testWithMultipleVersions():1', 22 | 'long%path%to%test%DeeplyNestedTest.testWithMultipleVersions():2', 23 | 'long%path%to%test%DeeplyNestedTest.testWithMultipleVersions():3', 24 | ] 25 | 26 | 27 | TEST_ID_DATA: list[tuple[str, str, int | None]] = [ 28 | ( 29 | 'single_version', 30 | 'test%AssertTest.test_assert_true()', 31 | 0, 32 | ), 33 | ( 34 | 'two_versions', 35 | 'test%AssertTest.setUp()', 36 | 1, 37 | ), 38 | ( 39 | 'deeply_nested_test', 40 | 'long%path%to%test%DeeplyNestedTest.testWithMultipleVersions()', 41 | 3, 42 | ), 43 | ( 44 | 'nonexistent_test', 45 | 'test%AssertTest.test_assert_false()', 46 | None, 47 | ), 48 | ] 49 | 50 | 51 | @pytest.mark.parametrize('test_id,test,expected_version', TEST_ID_DATA, ids=[test_id for test_id, *_ in TEST_ID_DATA]) 52 | def test_foundry_latest_proof_version( 53 | monkeypatch: MonkeyPatch, test_id: str, test: str, expected_version: int | None 54 | ) -> None: 55 | 56 | # Given 57 | monkeypatch.setattr(Foundry, '__init__', lambda _: None) 58 | monkeypatch.setattr(Foundry, 'list_proof_dir', mock_listdir) 59 | 60 | foundry = Foundry() # type: ignore 61 | 62 | latest_version = foundry.latest_proof_version(test) 63 | 64 | # Then 65 | assert latest_version == expected_version 66 | -------------------------------------------------------------------------------- /src/tests/unit/utils.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from pathlib import Path 4 | from typing import TYPE_CHECKING 5 | 6 | if TYPE_CHECKING: 7 | from typing import Final 8 | 9 | 10 | TEST_DATA_DIR: Final = (Path(__file__).parent / 'test-data').resolve(strict=True) 11 | -------------------------------------------------------------------------------- /src/tests/utils.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from shutil import copytree 4 | from typing import TYPE_CHECKING 5 | 6 | from pyk.utils import run_process_2 7 | 8 | from kontrol.foundry import Foundry 9 | 10 | if TYPE_CHECKING: 11 | from typing import Final 12 | from pathlib import Path 13 | 14 | from typing import TYPE_CHECKING 15 | 16 | FORGE_STD_REF: Final = '75f1746' 17 | 18 | 19 | def forge_build(test_data_dir: Path, target_dir: Path) -> Foundry: 20 | copytree(str(test_data_dir / 'foundry'), str(target_dir), dirs_exist_ok=True) 21 | run_process_2(['forge', 'install', '--no-git', f'foundry-rs/forge-std@{FORGE_STD_REF}'], cwd=target_dir) 22 | run_process_2(['forge', 'build'], cwd=target_dir) 23 | return Foundry(foundry_root=target_dir) 24 | --------------------------------------------------------------------------------