├── .eslintrc.json ├── .github └── workflows │ ├── node.js.yaml │ └── npm.yaml ├── .gitignore ├── .mocharc.json ├── .nvmrc ├── .nycrc.json ├── .prettierrc.json ├── .vscode └── settings.json ├── AUTHORS.md ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── src ├── ast_to_source_printer.ts ├── bin │ ├── scribble.ts │ └── scribble_cli.json ├── index.ts ├── instrumenter │ ├── annotations.ts │ ├── callgraph.ts │ ├── cha.ts │ ├── custom_maps.ts │ ├── custom_maps_templates.ts │ ├── deprecated_warnings.ts │ ├── index.ts │ ├── instrument.ts │ ├── instrumentation_context.ts │ ├── interpose.ts │ ├── state_var_instrumenter.ts │ ├── state_vars.ts │ ├── transpile.ts │ ├── transpiling_context.ts │ ├── type_string.ts │ ├── utils.ts │ └── utils_library.ts ├── logger │ ├── index.ts │ └── logger.ts ├── macros │ ├── index.ts │ └── utils.ts ├── rewriter │ ├── flatten.ts │ ├── import_directive.pegjs │ ├── import_directive_header.ts │ └── index.ts ├── spec-lang │ ├── ast │ │ ├── address_literal.ts │ │ ├── binary_operation.ts │ │ ├── boolean_literal.ts │ │ ├── conditional.ts │ │ ├── constants.ts │ │ ├── declarations │ │ │ ├── annotation.ts │ │ │ ├── if_assigned.ts │ │ │ ├── if_updated.ts │ │ │ ├── index.ts │ │ │ ├── let_annotation.ts │ │ │ ├── macro.ts │ │ │ ├── property.ts │ │ │ ├── state_var_prop.ts │ │ │ ├── try_annotation.ts │ │ │ ├── user_constant_definition.ts │ │ │ └── user_function_definition.ts │ │ ├── for_all.ts │ │ ├── function_call.ts │ │ ├── hex_literal.ts │ │ ├── identifier.ts │ │ ├── index.ts │ │ ├── index_access.ts │ │ ├── let.ts │ │ ├── member_access.ts │ │ ├── node.ts │ │ ├── number.ts │ │ ├── result.ts │ │ ├── string_literal.ts │ │ └── unary_operation.ts │ ├── expr_grammar.pegjs │ ├── expr_parser_header.ts │ └── tc │ │ ├── index.ts │ │ ├── internal_types │ │ ├── function_set_type.ts │ │ └── index.ts │ │ ├── semcheck.ts │ │ ├── typecheck.ts │ │ └── typeenv.ts └── util │ ├── arming.ts │ ├── errors.ts │ ├── fs.ts │ ├── index.ts │ ├── json_output.ts │ ├── location.ts │ ├── misc.ts │ ├── name_generator.ts │ ├── set.ts │ ├── sources.ts │ ├── unicode.ts │ └── yaml.ts ├── static ├── annotated_badge.png └── logo.png ├── stdlib ├── erc1155.scribble.yaml ├── erc20.scribble.yaml ├── erc721.scribble.yaml └── ownable.scribble.yaml ├── test ├── integration │ ├── artefacts.spec.ts │ ├── compatibility.spec.ts │ ├── multifile.spec.ts │ ├── propertymap.spec.ts │ ├── scribble │ │ ├── _.spec.ts │ │ ├── download_compilers.spec.ts │ │ ├── help.spec.ts │ │ ├── run │ │ │ ├── filtering.spec.ts │ │ │ ├── invalid.spec.ts │ │ │ └── valid.spec.ts │ │ └── version.spec.ts │ ├── src2srcmap.spec.ts │ ├── utils.ts │ ├── vm.spec.ts │ └── vm.ts ├── multifile_samples │ ├── arr_sum │ │ ├── flat.sol.expected │ │ ├── instrumentationMetadata.json.expected │ │ ├── main.sol │ │ └── main.sol.instrumented.expected │ ├── asserts │ │ ├── A.sol │ │ ├── B.sol │ │ ├── B.sol.instrumented.expected │ │ ├── C.sol │ │ ├── C.sol.instrumented.expected │ │ ├── flat.sol.expected │ │ └── instrumentationMetadata.json.expected │ ├── circular_imports │ │ ├── A.sol │ │ ├── A.sol.instrumented.expected │ │ ├── B.sol │ │ ├── B.sol.instrumented.expected │ │ ├── flat.sol.expected │ │ └── instrumentationMetadata.json.expected │ ├── custom_operators │ │ ├── flat.sol.expected │ │ ├── instrumentationMetadata.json.expected │ │ ├── operators.sol │ │ └── sample.sol │ ├── erc20_macro_inheritance │ │ ├── child.sol │ │ ├── child.sol.instrumented.expected │ │ ├── erc20_base.sol │ │ ├── erc20_base.sol.instrumented.expected │ │ ├── flat.sol.expected │ │ └── instrumentationMetadata.json.expected │ ├── forall_maps │ │ ├── base.sol │ │ ├── base.sol.instrumented.expected │ │ ├── child.sol │ │ ├── child.sol.instrumented.expected │ │ ├── flat.sol.expected │ │ └── instrumentationMetadata.json.expected │ ├── import_file_level_fn_and_var │ │ ├── A.sol │ │ ├── B.sol │ │ └── C.sol │ ├── import_rewrites │ │ ├── flat.sol.expected │ │ ├── imp1.sol │ │ ├── imp2.sol │ │ ├── imp3.sol │ │ ├── instrumentationMetadata.json.expected │ │ └── main.sol │ ├── inheritance1 │ │ ├── A.sol │ │ ├── B.sol │ │ ├── C.sol │ │ ├── D.sol │ │ ├── flat.sol.expected │ │ └── instrumentationMetadata.json.expected │ ├── macros │ │ ├── base.sol │ │ ├── base.sol.instrumented.expected │ │ ├── child.sol │ │ ├── child.sol.instrumented.expected │ │ ├── flat.sol.expected │ │ ├── instrumentationMetadata.json.expected │ │ ├── macro1.scribble.yaml │ │ └── macro2.scribble.yaml │ ├── node_modules_erc20 │ │ ├── contracts │ │ │ ├── Foo.sol │ │ │ └── Foo.sol.instrumented.expected │ │ ├── flat.sol.expected │ │ ├── instrumentationMetadata.json.expected │ │ └── node_modules │ │ │ └── @openzeppelin │ │ │ └── contracts │ │ │ ├── package.json │ │ │ ├── token │ │ │ └── ERC20 │ │ │ │ ├── ERC20.sol │ │ │ │ └── ERC20.sol.instrumented.expected │ │ │ └── utils │ │ │ ├── Context.sol │ │ │ └── Context.sol.instrumented.expected │ ├── node_modules_erc20_2 │ │ ├── contracts │ │ │ ├── Foo.sol │ │ │ └── Foo.sol.instrumented.expected │ │ ├── flat.sol.expected │ │ ├── instrumentationMetadata.json.expected │ │ └── node_modules │ │ │ └── @openzeppelin │ │ │ └── contracts │ │ │ ├── package.json │ │ │ ├── token │ │ │ └── ERC20 │ │ │ │ ├── ERC20.sol │ │ │ │ └── ERC20.sol.instrumented.expected │ │ │ └── utils │ │ │ ├── Context.sol │ │ │ └── Context.sol.instrumented.expected │ ├── node_modules_erc20_3 │ │ ├── contracts │ │ │ ├── Foo.sol │ │ │ └── Foo.sol.instrumented.expected │ │ ├── flat.sol.expected │ │ ├── instrumentationMetadata.json.expected │ │ └── node_modules │ │ │ └── @openzeppelin │ │ │ └── contracts │ │ │ ├── package.json │ │ │ ├── token │ │ │ └── ERC20 │ │ │ │ ├── ERC20.sol │ │ │ │ └── ERC20.sol.instrumented.expected │ │ │ └── utils │ │ │ ├── Context.sol │ │ │ └── Context.sol.instrumented.expected │ ├── proj1 │ │ ├── base.sol │ │ ├── base.sol.instrumented.expected │ │ ├── child1.sol │ │ ├── child1.sol.instrumented.expected │ │ ├── child2.sol │ │ ├── child2.sol.instrumented.expected │ │ ├── flat.sol.expected │ │ └── instrumentationMetadata.json.expected │ ├── reexported_imports │ │ ├── flat.sol.expected │ │ ├── imp1.sol │ │ ├── imp2.sol │ │ ├── imp3.sol │ │ ├── instrumentationMetadata.json.expected │ │ └── main.sol │ ├── reexported_imports_05 │ │ ├── flat.sol.expected │ │ ├── imp1.sol │ │ ├── imp2.sol │ │ ├── imp3.sol │ │ ├── instrumentationMetadata.json.expected │ │ └── main.sol │ └── using_for_free_funcs │ │ ├── flat.sol.expected │ │ ├── instrumentationMetadata.json.expected │ │ ├── sample.sol │ │ └── util.sol ├── samples │ ├── SimpleStorage.sol │ ├── arr_sum.instrumented.sol │ ├── arr_sum.sol │ ├── arr_sum.sol.json │ ├── assert.instrumented.sol │ ├── assert.sol │ ├── assert.sol.json │ ├── calldata_parameters.pre_0.6.9.instrumented.sol │ ├── calldata_parameters.pre_0.6.9.sol │ ├── calldata_parameters.pre_0.6.9.sol.json │ ├── calldata_paramteres.instrumented.sol │ ├── calldata_paramteres.sol │ ├── calldata_paramteres.sol.json │ ├── cha.sol │ ├── contract_decorated_ext_call.instrumented.sol │ ├── contract_decorated_ext_call.sol │ ├── contract_decorated_ext_call.sol.json │ ├── contract_decorated_ext_callv05.instrumented.sol │ ├── contract_decorated_ext_callv05.sol │ ├── contract_decorated_ext_callv05.sol.json │ ├── contract_multi_arg_debug.instrumented.sol │ ├── contract_multi_arg_debug.sol │ ├── contract_multi_arg_debug.sol.json │ ├── contract_pos.instrumented.sol │ ├── contract_pos.sol │ ├── contract_pos.sol.json │ ├── contract_pos_edge_cases.instrumented.sol │ ├── contract_pos_edge_cases.sol │ ├── contract_pos_edge_cases.sol.json │ ├── crashingAnnotation.instrumented.sol │ ├── crashingAnnotation.sol │ ├── crashingAnnotation.sol.json │ ├── custom_maps_0.4.26.instrumented.sol │ ├── custom_maps_0.4.26.sol │ ├── custom_maps_0.4.26.sol.json │ ├── dbg_event_tests.instrumented.sol │ ├── dbg_event_tests.sol │ ├── dbg_event_tests.sol.json │ ├── erc20_macro.instrumented.sol │ ├── erc20_macro.sol │ ├── erc20_macro.sol.json │ ├── erc721_macro.instrumented.sol │ ├── erc721_macro.sol │ ├── erc721_macro.sol.json │ ├── example_valentin.instrumented.sol │ ├── example_valentin.sol │ ├── example_valentin.sol.json │ ├── filtering.sol │ ├── forall_and_if_updated.instrumented.sol │ ├── forall_and_if_updated.sol │ ├── forall_and_if_updated.sol.json │ ├── forall_maps.instrumented.sol │ ├── forall_maps.sol │ ├── forall_maps.sol.json │ ├── forall_simple.instrumented.sol │ ├── forall_simple.sol │ ├── forall_simple.sol.json │ ├── hardhat │ │ └── console.sol │ ├── hardhat_test.instrumented.sol │ ├── hardhat_test.sol │ ├── hints.instrumented.sol │ ├── hints.sol │ ├── hints.sol.json │ ├── if_assigned_complex.instrumented.sol │ ├── if_assigned_complex.sol │ ├── if_assigned_complex.sol.json │ ├── if_assigned_inline_initializers.instrumented.sol │ ├── if_assigned_inline_initializers.sol │ ├── if_assigned_inline_initializers.sol.json │ ├── if_assigned_primitive.instrumented.sol │ ├── if_assigned_primitive.sol │ ├── if_assigned_primitive.sol.json │ ├── if_succeeds_on_contract.instrumented.sol │ ├── if_succeeds_on_contract.sol │ ├── if_succeeds_on_contract.sol.json │ ├── if_succeeds_on_contract_inheritance.instrumented.sol │ ├── if_succeeds_on_contract_inheritance.sol │ ├── if_succeeds_on_contract_inheritance.sol.json │ ├── if_succeeds_on_statement.instrumented.sol │ ├── if_succeeds_on_statement.sol │ ├── if_succeeds_on_statement.sol.json │ ├── if_updated_aliasing.instrumented.sol │ ├── if_updated_aliasing.sol │ ├── if_updated_aliasing.sol.json │ ├── if_updated_fun_return_ptr.instrumented.sol │ ├── if_updated_fun_return_ptr.sol │ ├── if_updated_inline_initializers.instrumented.sol │ ├── if_updated_inline_initializers.sol │ ├── if_updated_inline_initializers.sol.json │ ├── if_updated_primitive.instrumented.sol │ ├── if_updated_primitive.sol │ ├── if_updated_primitive.sol.json │ ├── if_updated_swap.instrumented.sol │ ├── if_updated_swap.sol │ ├── if_updated_swap.sol.json │ ├── if_updated_tuples.instrumented.sol │ ├── if_updated_tuples.sol │ ├── if_updated_tuples.sol.json │ ├── if_updated_unsafe.instrumented.sol │ ├── if_updated_unsafe.sol │ ├── if_updated_unsafe.sol.json │ ├── immutables.instrumented.sol │ ├── immutables.sol │ ├── immutables.sol.json │ ├── increment.instrumented.sol │ ├── increment.sol │ ├── increment.sol.json │ ├── increment_inherited.instrumented.sol │ ├── increment_inherited.sol │ ├── increment_inherited.sol.json │ ├── increment_inherited2.instrumented.sol │ ├── increment_inherited2.sol │ ├── increment_inherited2.sol.json │ ├── increment_inherited3.instrumented.sol │ ├── increment_inherited3.sol │ ├── increment_inherited3.sol.json │ ├── increment_inherited3_v06.instrumented.sol │ ├── increment_inherited3_v06.sol │ ├── increment_inherited3_v06.sol.json │ ├── increment_inherited4.instrumented.sol │ ├── increment_inherited4.sol │ ├── increment_inherited4.sol.json │ ├── increment_inherited_collision.instrumented.sol │ ├── increment_inherited_collision.sol │ ├── increment_inherited_collision.sol.json │ ├── increment_inheritedv6.instrumented.sol │ ├── increment_inheritedv6.sol │ ├── increment_inheritedv6.sol.json │ ├── increment_multiline.instrumented.sol │ ├── increment_multiline.sol │ ├── increment_multiline.sol.json │ ├── inheritance_specifiers.instrumented.sol │ ├── inheritance_specifiers.sol │ ├── inheritance_specifiers.sol.json │ ├── invalid │ │ ├── ambiguous_binding1.invalid.sol │ │ ├── ambiguous_binding2.invalid.sol │ │ ├── annotation_multiline2_syntax_error.invalid.sol │ │ ├── annotation_multiline_syntax_error.invalid.sol │ │ ├── annotation_sem_error.invalid.sol │ │ ├── annotation_syntax_error.invalid.sol │ │ ├── annotation_type_error.invalid.sol │ │ ├── assert_try_catch.invalid.sol │ │ ├── consts_diff_contracts.invalid.sol │ │ ├── consts_non_const.invalid.sol │ │ ├── consts_unordered.invalid.sol │ │ ├── deprecated_no_hash.warning.sol │ │ ├── deprecated_whitespace_natspec.warning.sol │ │ ├── erc20_macro.bad_var_type.invalid.sol │ │ ├── forall_iterator_type_incompatible.invalid.sol │ │ ├── forall_maps_aliasing1.invalid.sol │ │ ├── forall_maps_aliasing2.invalid.sol │ │ ├── garbage_at_start.warning.sol │ │ ├── if_succeeds_on_free_function.invalid.sol │ │ ├── if_updated_aliasing1.invalid.sol │ │ ├── if_updated_aliasing2.invalid.sol │ │ ├── if_updated_aliasing3.invalid.sol │ │ ├── if_updated_aliasing4.invalid.sol │ │ ├── if_updated_aliasing5.invalid.sol │ │ ├── if_updated_fun_return_ptr_bad.sol │ │ ├── if_updated_length.invalid.sol │ │ ├── if_updated_old_inline_initializer.invalid.sol │ │ ├── if_updated_push_ref.invalid.sol │ │ ├── immutables.sol │ │ ├── invalid_annotation.invalid.sol │ │ ├── invariant_on_function.invalid.sol │ │ ├── macro.bad_fun_arg_type.invalid.sol │ │ ├── macro.bad_schema1.invalid.yaml │ │ ├── macro.empty.invalid.yaml │ │ ├── macro.good_fun_arg_type.sol │ │ ├── macro.sem_error.invalid.yaml │ │ ├── macro.syntax_error.invalid.yaml │ │ ├── macro.syntax_error1.invalid.yaml │ │ ├── missing_terminator_semicolon.invalid.sol │ │ ├── ownable_macro.bad_var_type.invalid.sol │ │ ├── ownable_macro.no_var.invalid.sol │ │ ├── require.old.invalid.sol │ │ ├── require.svar.invalid.sol │ │ ├── try.old.invalid.sol │ │ ├── try.svar.invalid.sol │ │ ├── type_error.invalid.sol │ │ └── userDefinedTypesInFunction.invalid.sol │ ├── invariant_try_catch.instrumented.sol │ ├── invariant_try_catch.sol │ ├── invariant_try_catch.sol.json │ ├── let_annotation.instrumented.sol │ ├── let_annotation.sol │ ├── let_annotation.sol.json │ ├── library_annotation.instrumented.sol │ ├── library_annotation.sol │ ├── library_annotation.sol.json │ ├── macro_erc20_nested_vars.instrumented.sol │ ├── macro_erc20_nested_vars.sol │ ├── macro_erc20_nested_vars.sol.json │ ├── macros │ │ ├── foo.scribble.yaml │ │ └── myerc20.scribble.yaml │ ├── maps_sum.instrumented.sol │ ├── maps_sum.sol │ ├── maps_sum.sol.json │ ├── misc.instrumented.sol │ ├── misc.sol │ ├── misc.sol.json │ ├── misc_08.instrumented.sol │ ├── misc_08.sol │ ├── misc_08.sol.json │ ├── mixing_if_updated_and_forall.instrumented.sol │ ├── mixing_if_updated_and_forall.sol │ ├── mixing_if_updated_and_forall.sol.json │ ├── mutability.instrumented.sol │ ├── mutability.sol │ ├── mutability.sol.json │ ├── ownable_macro.instrumented.sol │ ├── ownable_macro.sol │ ├── ownable_macro.sol.json │ ├── predefined.instrumented.sol │ ├── predefined.sol │ ├── predefined.sol.json │ ├── skip_invariant_double_check.instrumented.sol │ ├── skip_invariant_double_check.sol │ ├── skip_invariant_double_check.sol.json │ ├── solidity_builtins_08.instrumented.sol │ ├── solidity_builtins_08.sol │ ├── solidity_builtins_08.sol.json │ ├── token_sale.instrumented.sol │ ├── token_sale.sol │ ├── token_sale.sol.json │ ├── unicode.instrumented.sol │ ├── unicode.sol │ └── vm │ │ ├── SimpleStorage.vm.json │ │ ├── arr_sum.vm.json │ │ ├── assert_forall.vm.json │ │ ├── assert_fun_call.vm.json │ │ ├── assert_mixed.vm.json │ │ ├── assert_simple.vm.json │ │ ├── calldata_parameters.instrumented.positive.vm.json │ │ ├── calldata_parameters.positive.vm.json │ │ ├── contract_multi_args_debug.negative.vm.json │ │ ├── contract_pos.instrumented.negative.vm.json │ │ ├── contract_pos.instrumented.positive.vm.json │ │ ├── contract_pos.negative.vm.json │ │ ├── contract_pos.positive.vm.json │ │ ├── contract_pos_constructor_fail.instrumented.negative.vm.json │ │ ├── contract_pos_constructor_fail.negative.vm.json │ │ ├── contract_pos_ext_call_fail.instrumented.negative.vm.json │ │ ├── contract_pos_ext_call_fail.negative.vm.json │ │ ├── contract_pos_library_interface.instrumented.negative.vm.json │ │ ├── contract_pos_library_interface.instrumented.positive.vm.json.disabled │ │ ├── contract_pos_library_interface.negative.vm.json │ │ ├── contract_pos_library_interface.positive.vm.json │ │ ├── dbg_event_tests.vm.json │ │ ├── eq_encoded.instrumented.vm.json │ │ ├── example_valentin.vm.json │ │ ├── forall_maps.vm.json │ │ ├── forall_simple.instrumented.negative.vm.json │ │ ├── forall_simple.negative.vm.json │ │ ├── if_updated_swap.vm.json │ │ ├── increment.instrumented.positive.vm.json │ │ ├── increment.positive.vm.json │ │ ├── increment_inherited.instrumented.positive.vm.json │ │ ├── increment_inherited.positive.vm.json │ │ ├── increment_inherited2.instrumented.negative.vm.json │ │ ├── increment_inherited2.instrumented.positive.vm.json │ │ ├── increment_inherited2.negative.vm.json │ │ ├── increment_inherited2.positive.vm.json │ │ ├── increment_inherited3.instrumented.negative.vm.json │ │ ├── increment_inherited3.instrumented.positive.vm.json │ │ ├── increment_inherited3.negative.vm.json │ │ ├── increment_inherited3.positive.vm.json │ │ ├── increment_inherited3_v06.instrumented.negative.vm.json │ │ ├── increment_inherited3_v06.instrumented.positive.vm.json │ │ ├── increment_inherited3_v06.negative.vm.json │ │ ├── increment_inherited3_v06.positive.vm.json │ │ ├── increment_inherited4.instrumented.negative.vm.json │ │ ├── increment_inherited4.negative.vm.json │ │ ├── increment_inherited_collision.instrumented.positive.vm.json │ │ ├── increment_inherited_collision.positive.vm.json │ │ ├── increment_inheritedv6.instrumented.positive.vm.json │ │ ├── increment_inheritedv6.positive.vm.json │ │ ├── maps_sum.vm.json │ │ ├── mixing_if_updated_and_forall.vm.json │ │ ├── unnamed_lets.instrumented.negative.vm.json │ │ ├── unnamed_lets.instrumented.positive.vm.json │ │ ├── unnamed_lets.negative.vm.json │ │ └── unnamed_lets.positive.vm.json └── unit │ ├── callgraph.spec.ts │ ├── cha.spec.ts │ ├── custom_maps.spec.ts │ ├── interposing.spec.ts │ ├── parser.spec.ts │ ├── sc.spec.ts │ ├── statevars.spec.ts │ ├── tc.spec.ts │ └── utils.ts └── tsconfig.json /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@typescript-eslint/parser", 3 | "env": { 4 | "node": true, 5 | "es6": true 6 | }, 7 | "plugins": ["@typescript-eslint"], 8 | "extends": [ 9 | "eslint:recommended", 10 | "plugin:@typescript-eslint/eslint-recommended", 11 | "plugin:@typescript-eslint/recommended", 12 | "plugin:prettier/recommended", 13 | "prettier" 14 | ], 15 | "rules": { 16 | "no-var": "error", 17 | "no-constant-condition": "off", 18 | "comma-dangle": ["error", "never"], 19 | 20 | "@typescript-eslint/no-explicit-any": "off", 21 | "@typescript-eslint/no-var-requires": "off", 22 | "@typescript-eslint/no-this-alias": "off", 23 | "@typescript-eslint/explicit-function-return-type": "off", 24 | "@typescript-eslint/array-type": ["error", { "default": "array-simple" }], 25 | "@typescript-eslint/no-use-before-define": ["error", { "functions": false }], 26 | "@typescript-eslint/explicit-module-boundary-types": [ 27 | "error", 28 | { "allowArgumentsExplicitlyTypedAsAny": true } 29 | ] 30 | }, 31 | "ignorePatterns": [ 32 | "src/spec-lang/expr_parser_header.ts", 33 | "src/spec-lang/expr_parser.ts", 34 | "src/rewriter/import_directive_parser.ts", 35 | "src/rewriter/import_directive_header.ts" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /.github/workflows/npm.yaml: -------------------------------------------------------------------------------- 1 | name: Build and release package 2 | 3 | on: 4 | release: 5 | types: [ published ] 6 | 7 | permissions: read-all 8 | 9 | jobs: 10 | publish: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | - uses: actions/setup-node@v4 15 | with: 16 | node-version: 20 17 | registry-url: "https://registry.npmjs.org" 18 | - run: npm install 19 | - run: npm publish 20 | env: 21 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .nyc_output 2 | node_modules 3 | dist 4 | coverage 5 | *.tgz 6 | src/spec-lang/expr_parser.ts 7 | src/spec-lang/annotation_parser.ts 8 | src/spec-lang/typeString_parser.ts 9 | src/rewriter/import_directive_parser.ts 10 | .vscode/launch.json 11 | test/multifile_samples/*/__scribble_ReentrancyUtils.sol 12 | test/multifile_samples/*/*.sol.instrumented 13 | .idea 14 | -------------------------------------------------------------------------------- /.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "package": "./package.json", 3 | "timeout": false, 4 | "require": "ts-node/register", 5 | "spec": ["./test/unit/**/*.spec.ts", "./test/integration/**/*.spec.ts"] 6 | } 7 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 20.11.0 -------------------------------------------------------------------------------- /.nycrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extension": [".ts"], 3 | "exclude": [ 4 | "**/*.d.ts", 5 | "**/node_modules/**", 6 | "**/test/**", 7 | "**/coverage/**", 8 | "**/.compiler_cache/**", 9 | "**/src/spec-lang/*_parser.ts", 10 | "**/src/spec-lang/*_parser_header.ts", 11 | "**/src/rewriter/*_parser.ts", 12 | "**/src/rewriter/*_header.ts" 13 | ], 14 | "reporter": ["lcov", "text-summary"], 15 | "all": true, 16 | "check-coverage": true, 17 | "statements": 90, 18 | "branches": 85, 19 | "functions": 90, 20 | "lines": 90 21 | } 22 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "always", 3 | "trailingComma": "none", 4 | "tabWidth": 4, 5 | "semi": true, 6 | "singleQuote": false, 7 | "printWidth": 100, 8 | "bracketSpacing": true 9 | } 10 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[javascript]": { 3 | "editor.defaultFormatter": "dbaeumer.vscode-eslint" 4 | }, 5 | "[javascriptreact]": { 6 | "editor.defaultFormatter": "dbaeumer.vscode-eslint" 7 | }, 8 | "[typescript]": { 9 | "editor.defaultFormatter": "dbaeumer.vscode-eslint" 10 | }, 11 | "[typescriptreact]": { 12 | "editor.defaultFormatter": "dbaeumer.vscode-eslint" 13 | }, 14 | "[json]": { 15 | "editor.defaultFormatter": "esbenp.prettier-vscode" 16 | }, 17 | "editor.defaultFormatter": "esbenp.prettier-vscode", 18 | "editor.formatOnSave": true, 19 | "json.format.enable": false, 20 | "eslint.alwaysShowStatus": true, 21 | "eslint.validate": ["javascript", "typescript"], 22 | "editor.codeActionsOnSave": { 23 | "source.fixAll.eslint": "explicit" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /AUTHORS.md: -------------------------------------------------------------------------------- 1 | Dimitar Bounov (https://github.com/cd1m0) 2 | Pavel Zverev (https://github.com/blitz-1306) 3 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Package main entry point. 3 | * 4 | * IDEs and hosting packages are exploring functionality, 5 | * starting from this file. 6 | * 7 | * Generally, this file should only re-export a top-level package API. 8 | */ 9 | export * from "./instrumenter"; 10 | export * from "./util"; 11 | -------------------------------------------------------------------------------- /src/instrumenter/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./interpose"; 2 | export * from "./annotations"; 3 | export * from "./instrument"; 4 | export * from "./transpile"; 5 | export * from "./state_vars"; 6 | export * from "./state_var_instrumenter"; 7 | export * from "./custom_maps_templates"; 8 | export * from "./custom_maps"; 9 | export * from "./utils"; 10 | export * from "./deprecated_warnings"; 11 | -------------------------------------------------------------------------------- /src/logger/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./logger"; 2 | -------------------------------------------------------------------------------- /src/logger/logger.ts: -------------------------------------------------------------------------------- 1 | const LogPlease = require("logplease"); 2 | 3 | export enum LogNameSpaces { 4 | Parser = "parser" 5 | } 6 | 7 | class LoggerManager { 8 | private levels = ["DEBUG", "INFO", "WARN", "ERROR", "NONE"]; 9 | private defaultName = "global"; 10 | 11 | private instances: { [name: string]: any } = {}; 12 | private allowed?: string[]; 13 | 14 | constructor(level: string, allowed?: string[]) { 15 | if (this.levels.includes(level)) { 16 | LogPlease.setLogLevel(level); 17 | } else { 18 | throw new Error(`Invalid log level ${level}. Valid levels: ${this.levels.join(", ")}`); 19 | } 20 | 21 | this.allowed = allowed; 22 | } 23 | 24 | isAllowed(name: string): boolean { 25 | return this.allowed === undefined || this.allowed.includes(name); 26 | } 27 | 28 | debug(message: string, name?: string) { 29 | name = name || this.defaultName; 30 | 31 | if (this.isAllowed(name)) { 32 | this.getInstance(name).debug(message); 33 | } 34 | } 35 | 36 | private getInstance(name: string): any { 37 | if (!(name in this.instances)) { 38 | this.instances[name] = LogPlease.create(name); 39 | } 40 | 41 | return this.instances[name]; 42 | } 43 | } 44 | 45 | const envLevel = process.env.DEBUG_LEVEL ? process.env.DEBUG_LEVEL.toUpperCase() : "NONE"; 46 | const envAllowed = process.env.DEBUG_FILTER ? process.env.DEBUG_FILTER.split(",") : undefined; 47 | 48 | export const Logger = new LoggerManager(envLevel, envAllowed); 49 | -------------------------------------------------------------------------------- /src/macros/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./utils"; 2 | -------------------------------------------------------------------------------- /src/rewriter/import_directive_header.ts: -------------------------------------------------------------------------------- 1 | // Need the ts-nocheck to suppress the noUnusedLocals errors in the generated parser 2 | // @ts-nocheck 3 | export interface SymbolDesc { 4 | name: string; 5 | alias: string | null; 6 | } 7 | 8 | export interface ImportDirectiveDesc { 9 | path: string; 10 | unitAlias: string | undefined; 11 | symbolAliases: SymbolDesc[]; 12 | } 13 | -------------------------------------------------------------------------------- /src/rewriter/index.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ConsenSysDiligence/scribble/8fef54864fa77527825714eab26d50b7823be4fa/src/rewriter/index.ts -------------------------------------------------------------------------------- /src/spec-lang/ast/address_literal.ts: -------------------------------------------------------------------------------- 1 | import { NodeLocation, SNode } from "./node"; 2 | 3 | export class SAddressLiteral extends SNode { 4 | public readonly val: string; 5 | 6 | constructor(val: string, src?: NodeLocation) { 7 | super(src); 8 | this.val = val; 9 | } 10 | 11 | pp(): string { 12 | return this.val; 13 | } 14 | 15 | getFields(): any[] { 16 | return [this.val]; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/spec-lang/ast/binary_operation.ts: -------------------------------------------------------------------------------- 1 | import { NodeLocation, SNode } from "./node"; 2 | 3 | export type PowerBinaryOperator = "**"; 4 | export type MultiplicativeBinaryOperator = "*" | "/" | "%"; 5 | export type AdditiveBinaryOperator = "+" | "-"; 6 | export type ShiftBinaryOperator = "<<" | ">>"; 7 | export type RelationalBinaryOperator = "<" | ">" | "<=" | ">="; 8 | export type EqualityOperator = "==" | "!="; 9 | export type BitwiseBinaryOperator = "&" | "|" | "^"; 10 | export type LogicalBinaryOperator = "&&" | "||"; 11 | export type ImplicationOperator = "==>"; 12 | 13 | export type BinaryOperator = 14 | | PowerBinaryOperator 15 | | MultiplicativeBinaryOperator 16 | | AdditiveBinaryOperator 17 | | ShiftBinaryOperator 18 | | RelationalBinaryOperator 19 | | EqualityOperator 20 | | BitwiseBinaryOperator 21 | | LogicalBinaryOperator 22 | | ImplicationOperator; 23 | 24 | export class SBinaryOperation extends SNode { 25 | public readonly left: SNode; 26 | public readonly op: BinaryOperator; 27 | public readonly right: SNode; 28 | 29 | constructor(left: SNode, op: BinaryOperator, right: SNode, src?: NodeLocation) { 30 | super(src); 31 | this.left = left; 32 | this.op = op; 33 | this.right = right; 34 | } 35 | 36 | pp(): string { 37 | return `(${this.left.pp()} ${this.op} ${this.right.pp()})`; 38 | } 39 | 40 | getFields(): any[] { 41 | return [this.left, this.op, this.right]; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/spec-lang/ast/boolean_literal.ts: -------------------------------------------------------------------------------- 1 | import { NodeLocation, SNode } from "./node"; 2 | 3 | export class SBooleanLiteral extends SNode { 4 | public readonly val: boolean; 5 | constructor(val: boolean, src?: NodeLocation) { 6 | super(src); 7 | this.val = val; 8 | } 9 | 10 | pp(): string { 11 | return String(this.val); 12 | } 13 | 14 | getFields(): any[] { 15 | return [this.val]; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/spec-lang/ast/conditional.ts: -------------------------------------------------------------------------------- 1 | import { NodeLocation, SNode } from "./node"; 2 | 3 | export class SConditional extends SNode { 4 | condition: SNode; 5 | trueExp: SNode; 6 | falseExp: SNode; 7 | 8 | constructor(condition: SNode, trueExp: SNode, falseExp: SNode, src?: NodeLocation) { 9 | super(src); 10 | this.condition = condition; 11 | this.trueExp = trueExp; 12 | this.falseExp = falseExp; 13 | } 14 | 15 | pp(): string { 16 | return `(${this.condition.pp()} ? ${this.falseExp.pp()} : ${this.falseExp.pp()})`; 17 | } 18 | 19 | getFields(): any[] { 20 | return [this.condition, this.trueExp, this.falseExp]; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/spec-lang/ast/constants.ts: -------------------------------------------------------------------------------- 1 | export enum ScribbleBuiltinFunctions { 2 | unchecked_sum = "unchecked_sum", 3 | eq_encoded = "eq_encoded" 4 | } 5 | 6 | export enum SolidityBuiltinFunctions { 7 | type = "type" 8 | } 9 | -------------------------------------------------------------------------------- /src/spec-lang/ast/declarations/if_assigned.ts: -------------------------------------------------------------------------------- 1 | import { AnnotationType } from "."; 2 | import { NodeLocation, SNode } from "../node"; 3 | import { AnnotationMD } from "./annotation"; 4 | import { DatastructurePath, SStateVarProp } from "./state_var_prop"; 5 | 6 | /** 7 | * `SIfAssigned` is a state var property checked only at the assignment/deletion of an EXACT 8 | * part of a state var property, as defined by the provided datastructure path. 9 | * 10 | * For example if you have `if_assigned[i] ...` for some array `a`, that property won't get 11 | * checked if you re-assign the whole array `a = []`. 12 | * 13 | */ 14 | export class SIfAssigned extends SStateVarProp { 15 | constructor(expression: SNode, path: DatastructurePath, md?: AnnotationMD, src?: NodeLocation) { 16 | super(AnnotationType.IfAssigned, expression, path, md, src); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/spec-lang/ast/declarations/if_updated.ts: -------------------------------------------------------------------------------- 1 | import { assert } from "solc-typed-ast"; 2 | import { AnnotationType } from "."; 3 | import { NodeLocation, SNode } from "../node"; 4 | import { AnnotationMD } from "./annotation"; 5 | import { DatastructurePath, SStateVarProp } from "./state_var_prop"; 6 | 7 | /** 8 | * `SIfUpdated` is a state var property refering to ANY update concerning the 9 | * state var or a part of it. Currently doesn't support adding a datastructure 10 | * path due to the not-yet well defined semantics of old() and new values in 11 | * the cases where a part of a complex data structure is destroyed/created. In 12 | * those case old/new values may not be defined. 13 | * 14 | * Furthremore, in a situation where we have `if_updated[i] ...` for some array 15 | * `arr` when we reassign/delete the whole array, its not yet defined for which 16 | * values we call `if_updated arr[i]`. All the old ones? All the new ones? The 17 | * minimum intersection of old and new? 18 | * 19 | */ 20 | export class SIfUpdated extends SStateVarProp { 21 | constructor(expression: SNode, path: DatastructurePath, md?: AnnotationMD, src?: NodeLocation) { 22 | assert(path.length === 0, "Not yet support if_updated with a path"); 23 | 24 | super(AnnotationType.IfUpdated, expression, path, md, src); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/spec-lang/ast/declarations/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./annotation"; 2 | export * from "./property"; 3 | export * from "./user_constant_definition"; 4 | export * from "./user_function_definition"; 5 | export * from "./state_var_prop"; 6 | export * from "./if_updated"; 7 | export * from "./if_assigned"; 8 | export * from "./macro"; 9 | export * from "./let_annotation"; 10 | export * from "./try_annotation"; 11 | -------------------------------------------------------------------------------- /src/spec-lang/ast/declarations/let_annotation.ts: -------------------------------------------------------------------------------- 1 | import { SId } from ".."; 2 | import { NodeLocation, SNode } from "../node"; 3 | import { AnnotationMD, AnnotationType, SAnnotation } from "./annotation"; 4 | 5 | export class SLetAnnotation extends SAnnotation { 6 | public readonly name: SId; 7 | public readonly expression: SNode; 8 | 9 | constructor( 10 | type: AnnotationType, 11 | name: SId, 12 | expression: SNode, 13 | md?: AnnotationMD, 14 | src?: NodeLocation 15 | ) { 16 | super(type, md, src); 17 | this.name = name; 18 | this.expression = expression; 19 | } 20 | 21 | getFields(): any[] { 22 | return [this.type, this.expression, this.label]; 23 | } 24 | 25 | pp(): string { 26 | return `${this.type} ${ 27 | this.label ? `{:msg "${this.label}"} ` : "" 28 | } ${this.name.pp()} := ${this.expression.pp()};`; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/spec-lang/ast/declarations/macro.ts: -------------------------------------------------------------------------------- 1 | import { SId } from "../identifier"; 2 | import { NodeLocation } from "../node"; 3 | import { AnnotationMD, AnnotationType, SAnnotation } from "./annotation"; 4 | 5 | export class SMacro extends SAnnotation { 6 | public readonly name: SId; 7 | public readonly parameters: SId[]; 8 | 9 | constructor(name: SId, params: SId[], md?: AnnotationMD, src?: NodeLocation) { 10 | super(AnnotationType.Macro, md, src); 11 | 12 | this.name = name; 13 | this.parameters = params; 14 | } 15 | 16 | getFields(): any[] { 17 | return [this.name, ...this.parameters]; 18 | } 19 | 20 | pp(): string { 21 | const paramStr = this.parameters.map((param) => param.pp()).join(", "); 22 | 23 | return `${this.type} ${ 24 | this.label ? `{:msg "${this.label}"} ` : "" 25 | }${this.name.pp()}(${paramStr})`; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/spec-lang/ast/declarations/property.ts: -------------------------------------------------------------------------------- 1 | import { NodeLocation, SNode } from "../node"; 2 | import { AnnotationMD, AnnotationType, SAnnotation } from "./annotation"; 3 | 4 | export class SProperty extends SAnnotation { 5 | public readonly expression: SNode; 6 | constructor(type: AnnotationType, expression: SNode, md?: AnnotationMD, src?: NodeLocation) { 7 | super(type, md, src); 8 | this.expression = expression; 9 | } 10 | 11 | getFields(): any[] { 12 | return [this.type, this.expression, this.label]; 13 | } 14 | 15 | pp(): string { 16 | return `${this.type} ${ 17 | this.label ? `{:msg "${this.label}"} ` : "" 18 | }${this.expression.pp()};`; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/spec-lang/ast/declarations/state_var_prop.ts: -------------------------------------------------------------------------------- 1 | import { AnnotationType } from "."; 2 | import { SId } from "../identifier"; 3 | import { NodeLocation, SNode } from "../node"; 4 | import { AnnotationMD } from "./annotation"; 5 | import { SProperty } from "./property"; 6 | 7 | /** 8 | * A path inside of a complex data structure. The `SId` components correspond to indexing inside of an array/map. The 9 | * `string` components correspond to field lookups inside structs. 10 | */ 11 | export type DatastructurePath = Array; 12 | /** 13 | * `SIfUpdated` is a special kind of property annotation that can also 14 | * make bindings refering to datastructure indices 15 | */ 16 | export class SStateVarProp extends SProperty { 17 | public readonly datastructurePath: DatastructurePath; 18 | 19 | constructor( 20 | annotationType: AnnotationType, 21 | expression: SNode, 22 | path: DatastructurePath, 23 | md?: AnnotationMD, 24 | src?: NodeLocation 25 | ) { 26 | super(annotationType, expression, md, src); 27 | this.datastructurePath = path; 28 | } 29 | 30 | getFields(): any[] { 31 | return [this.type, this.expression, ...this.datastructurePath, this.label]; 32 | } 33 | 34 | pp(): string { 35 | const path = this.datastructurePath 36 | .map((element) => (element instanceof SId ? `[${element.name}]` : `.${element}`)) 37 | .join(""); 38 | return `${this.type}${path} ${ 39 | this.label ? `{:msg "${this.label}"} ` : "" 40 | }${this.expression.pp()};`; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/spec-lang/ast/declarations/try_annotation.ts: -------------------------------------------------------------------------------- 1 | import { AnnotationType } from "."; 2 | import { NodeLocation, SNode } from "../node"; 3 | import { AnnotationMD, SAnnotation } from "./annotation"; 4 | 5 | /** 6 | * `STryAnnotation` is a special kind of property annotation 7 | * that is able to accept several expressions. 8 | */ 9 | export class STryAnnotation extends SAnnotation { 10 | readonly exprs: SNode[]; 11 | 12 | constructor(type: AnnotationType, exprs: SNode[], md?: AnnotationMD, src?: NodeLocation) { 13 | super(type, md, src); 14 | 15 | this.exprs = exprs; 16 | } 17 | 18 | getFields(): any[] { 19 | return [this.type, ...this.exprs, this.label]; 20 | } 21 | 22 | pp(): string { 23 | const args = this.exprs.map((arg) => arg.pp()).join(", "); 24 | 25 | return `${this.type} ${this.label ? `{:msg "${this.label}"} ` : ""}${args};`; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/spec-lang/ast/declarations/user_constant_definition.ts: -------------------------------------------------------------------------------- 1 | import { TypeNode } from "solc-typed-ast"; 2 | import { SId } from "../identifier"; 3 | import { NodeLocation, SNode } from "../node"; 4 | import { AnnotationMD, AnnotationType, SAnnotation } from "./annotation"; 5 | 6 | export class SUserConstantDefinition extends SAnnotation { 7 | readonly name: SId; 8 | readonly formalType: TypeNode; 9 | readonly value: SNode; 10 | 11 | constructor( 12 | name: SId, 13 | formalType: TypeNode, 14 | value: SNode, 15 | md?: AnnotationMD, 16 | src?: NodeLocation 17 | ) { 18 | super(AnnotationType.Const, md, src); 19 | 20 | this.name = name; 21 | this.formalType = formalType; 22 | this.value = value; 23 | } 24 | 25 | getFields(): any[] { 26 | return [this.name, this.formalType, this.value]; 27 | } 28 | 29 | pp(): string { 30 | return `const ${this.label ? `{:msg "${this.label}"} ` : ""}${this.formalType.pp()} ${ 31 | this.name.name 32 | } := ${this.value.pp()}`; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/spec-lang/ast/declarations/user_function_definition.ts: -------------------------------------------------------------------------------- 1 | import { TypeNode } from "solc-typed-ast"; 2 | import { SId } from "../identifier"; 3 | import { NodeLocation, SNode } from "../node"; 4 | import { AnnotationMD, AnnotationType, SAnnotation } from "./annotation"; 5 | 6 | export class SUserFunctionDefinition extends SAnnotation { 7 | public readonly name: SId; 8 | public readonly parameters: Array<[SId, TypeNode]>; 9 | public readonly returnType: TypeNode; 10 | public readonly body: SNode; 11 | 12 | constructor( 13 | name: SId, 14 | params: Array<[SId, TypeNode]>, 15 | returnType: TypeNode, 16 | body: SNode, 17 | md?: AnnotationMD, 18 | src?: NodeLocation 19 | ) { 20 | super(AnnotationType.Define, md, src); 21 | this.name = name; 22 | this.parameters = params; 23 | this.returnType = returnType; 24 | this.body = body; 25 | } 26 | 27 | getFields(): any[] { 28 | return [this.name, ...this.parameters.map((x) => x[0]), this.returnType, this.body]; 29 | } 30 | 31 | pp(): string { 32 | const paramStr = this.parameters 33 | .map(([name, type]) => `${type.pp()} ${name.name}`) 34 | .join(", "); 35 | return `define ${this.label ? `{:msg "${this.label}"} ` : ""}${ 36 | this.name.name 37 | }(${paramStr}) ${this.returnType.pp()} = ${this.body.pp()}`; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/spec-lang/ast/function_call.ts: -------------------------------------------------------------------------------- 1 | import { NodeLocation, SNode } from "./node"; 2 | import { TypeNode } from "solc-typed-ast"; 3 | 4 | export class SFunctionCall extends SNode { 5 | callee: SNode | TypeNode; 6 | args: SNode[]; 7 | 8 | constructor(callee: SNode, args: SNode[], src?: NodeLocation) { 9 | super(src); 10 | this.callee = callee; 11 | this.args = args; 12 | } 13 | 14 | pp(): string { 15 | return `${this.callee.pp()}(${this.args.map((arg) => arg.pp()).join(",")})`; 16 | } 17 | 18 | getFields(): any[] { 19 | return [this.callee, ...this.args]; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/spec-lang/ast/hex_literal.ts: -------------------------------------------------------------------------------- 1 | import { NodeLocation, SNode } from "./node"; 2 | 3 | export class SHexLiteral extends SNode { 4 | public readonly val: string; 5 | 6 | constructor(val: string, src?: NodeLocation) { 7 | super(src); 8 | 9 | this.val = val; 10 | } 11 | 12 | pp(): string { 13 | return `hex"${this.val}"`; 14 | } 15 | 16 | getFields(): any[] { 17 | return [this.val]; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/spec-lang/ast/identifier.ts: -------------------------------------------------------------------------------- 1 | import { ImportDirective, VariableDeclaration } from "solc-typed-ast"; 2 | import { SForAll, SLet } from "."; 3 | import { StateVarScope } from "../tc"; 4 | import { SLetAnnotation, SUserConstantDefinition, SUserFunctionDefinition } from "./declarations"; 5 | import { NodeLocation, SNode } from "./node"; 6 | 7 | export type VarDefSite = 8 | | VariableDeclaration 9 | | [SLet, number] 10 | | [SUserFunctionDefinition, number] 11 | | [StateVarScope, number] 12 | | SForAll 13 | | SLetAnnotation; 14 | 15 | export type IdDefSite = 16 | | VarDefSite 17 | | "function_name" 18 | | "type_name" 19 | | "this" 20 | | SUserFunctionDefinition 21 | | SUserConstantDefinition 22 | | "builtin_fun" 23 | | ImportDirective; 24 | 25 | export class SId extends SNode { 26 | name: string; 27 | 28 | /** 29 | * AST Node corresponding to the definition for this SId. This is set during type-checking 30 | */ 31 | defSite?: IdDefSite; 32 | 33 | constructor(name: string, src?: NodeLocation) { 34 | super(src); 35 | this.name = name; 36 | } 37 | 38 | pp(): string { 39 | return this.name; 40 | } 41 | 42 | getFields(): any[] { 43 | return [this.name]; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/spec-lang/ast/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./node"; 2 | export * from "./identifier"; 3 | export * from "./number"; 4 | export * from "./boolean_literal"; 5 | export * from "./hex_literal"; 6 | export * from "./string_literal"; 7 | export * from "./unary_operation"; 8 | export * from "./binary_operation"; 9 | export * from "./member_access"; 10 | export * from "./index_access"; 11 | export * from "./function_call"; 12 | export * from "./conditional"; 13 | export * from "./let"; 14 | export * from "./address_literal"; 15 | export * from "./result"; 16 | export * from "./declarations"; 17 | export * from "./for_all"; 18 | export * from "./constants"; 19 | -------------------------------------------------------------------------------- /src/spec-lang/ast/index_access.ts: -------------------------------------------------------------------------------- 1 | import { NodeLocation, SNode } from "./node"; 2 | 3 | export class SIndexAccess extends SNode { 4 | base: SNode; 5 | index: SNode; 6 | 7 | constructor(base: SNode, index: SNode, src?: NodeLocation) { 8 | super(src); 9 | this.base = base; 10 | this.index = index; 11 | } 12 | 13 | pp(): string { 14 | return `${this.base.pp()}[${this.index.pp()}]`; 15 | } 16 | 17 | getFields(): any[] { 18 | return [this.base, this.index]; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/spec-lang/ast/let.ts: -------------------------------------------------------------------------------- 1 | import { NodeLocation, SNode } from "./node"; 2 | import { SId } from "."; 3 | 4 | export class SLet extends SNode { 5 | lhs: SId[]; 6 | rhs: SNode; 7 | in: SNode; 8 | 9 | constructor(lhs: SId[], rhs: SNode, inExp: SNode, src?: NodeLocation) { 10 | super(src); 11 | this.lhs = lhs; 12 | this.rhs = rhs; 13 | this.in = inExp; 14 | } 15 | 16 | pp(): string { 17 | return `(let ${this.lhs 18 | .map((v) => v.pp()) 19 | .join(",")} := ${this.rhs.pp()} in ${this.in.pp()})`; 20 | } 21 | 22 | getFields(): any[] { 23 | return [...this.lhs, this.rhs, this.in]; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/spec-lang/ast/member_access.ts: -------------------------------------------------------------------------------- 1 | import { ExportedSymbol } from "solc-typed-ast"; 2 | import { NodeLocation, SNode } from "./node"; 3 | 4 | export class SMemberAccess extends SNode { 5 | base: SNode; 6 | member: string; 7 | public defSite?: ExportedSymbol; 8 | 9 | constructor(base: SNode, member: string, src?: NodeLocation) { 10 | super(src); 11 | this.base = base; 12 | this.member = member; 13 | } 14 | 15 | pp(): string { 16 | return `${this.base.pp()}.${this.member}`; 17 | } 18 | 19 | getFields(): any[] { 20 | return [this.base, this.member]; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/spec-lang/ast/number.ts: -------------------------------------------------------------------------------- 1 | import { NodeLocation, SNode } from "./node"; 2 | 3 | const unitMultiplier = new Map([ 4 | ["wei", BigInt(1)], 5 | ["gwei", BigInt(1e9)], 6 | ["ether", BigInt(1e18)], 7 | ["seconds", BigInt(1)], 8 | ["minutes", BigInt(60)], 9 | ["hours", BigInt(3600)], 10 | ["days", BigInt(86400)], 11 | ["weeks", BigInt(604800)] 12 | ]); 13 | 14 | export class SNumber extends SNode { 15 | public readonly num: bigint; 16 | public readonly radix: number; 17 | 18 | constructor(num: bigint, radix: number, src?: NodeLocation, type?: string) { 19 | super(src); 20 | 21 | this.radix = radix; 22 | 23 | if (type) { 24 | const multiplier = unitMultiplier.get(type); 25 | 26 | if (multiplier === undefined) { 27 | throw new Error("Unknown denomination unit: " + type); 28 | } 29 | 30 | this.num = num * multiplier; 31 | } else { 32 | this.num = num; 33 | } 34 | } 35 | 36 | pp(): string { 37 | let numStr = this.num.toString(this.radix); 38 | 39 | if (this.radix === 16) { 40 | if (numStr.length % 2 !== 0) { 41 | numStr = "0" + numStr; 42 | } 43 | 44 | return "0x" + numStr; 45 | } 46 | 47 | return numStr; 48 | } 49 | 50 | getFields(): any[] { 51 | return [this.num, this.radix]; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/spec-lang/ast/result.ts: -------------------------------------------------------------------------------- 1 | import { NodeLocation, SNode } from "./node"; 2 | 3 | export class SResult extends SNode { 4 | constructor(src?: NodeLocation) { 5 | super(src); 6 | } 7 | 8 | pp(): string { 9 | return "$result"; 10 | } 11 | 12 | getFields(): any[] { 13 | return []; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/spec-lang/ast/string_literal.ts: -------------------------------------------------------------------------------- 1 | import { NodeLocation, SNode } from "./node"; 2 | 3 | export class SStringLiteral extends SNode { 4 | public readonly val: string; 5 | 6 | constructor(val: string, src?: NodeLocation) { 7 | super(src); 8 | 9 | this.val = val; 10 | } 11 | 12 | pp(): string { 13 | return JSON.stringify(this.val); 14 | } 15 | 16 | getFields(): any[] { 17 | return [this.val]; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/spec-lang/ast/unary_operation.ts: -------------------------------------------------------------------------------- 1 | import { NodeLocation, SNode } from "./node"; 2 | 3 | export type UnaryOperator = "-" | "!" | "old"; 4 | 5 | export class SUnaryOperation extends SNode { 6 | public readonly op: UnaryOperator; 7 | public readonly subexp: SNode; 8 | 9 | constructor(op: UnaryOperator, subexp: SNode, src?: NodeLocation) { 10 | super(src); 11 | this.op = op; 12 | this.subexp = subexp; 13 | } 14 | 15 | pp(): string { 16 | if (this.op === "old") { 17 | return `old(${this.subexp.pp()})`; 18 | } 19 | 20 | return `(${this.op}${this.subexp.pp()})`; 21 | } 22 | 23 | getFields(): any[] { 24 | return [this.op, this.subexp]; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/spec-lang/tc/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./typecheck"; 2 | export * from "./semcheck"; 3 | export * from "./typeenv"; 4 | -------------------------------------------------------------------------------- /src/spec-lang/tc/internal_types/function_set_type.ts: -------------------------------------------------------------------------------- 1 | import { 2 | TypeNode, 3 | FunctionDefinition, 4 | VariableDeclaration, 5 | ContractDefinition 6 | } from "solc-typed-ast"; 7 | import { Range } from "../../../util/location"; 8 | import { SNode } from "../../ast"; 9 | 10 | /** 11 | * Internal class used during type-checking to carry information for the possible overloaded targets 12 | * of a callee, back to the callsite which can resolve based on the actual arguments. 13 | * 14 | * @todo This class is slightly different from the one, that is provided by solc-typed-ast. 15 | * Wondering if it can be reconsidered somehow. 16 | */ 17 | export class FunctionSetType extends TypeNode { 18 | public definitions: Array; 19 | public readonly defaultArg: SNode | undefined; 20 | 21 | constructor( 22 | definitions: Array, 23 | defaultArg: SNode | undefined = undefined, 24 | src?: Range 25 | ) { 26 | super(src); 27 | this.definitions = definitions; 28 | this.defaultArg = defaultArg; 29 | } 30 | 31 | pp(): string { 32 | return `<${this.definitions 33 | .map((def) => `${(def.vScope as ContractDefinition).name}.${def.name}`) 34 | .join(",")}>`; 35 | } 36 | 37 | getFields(): any[] { 38 | return [this.definitions.map((def) => def.id)]; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/spec-lang/tc/internal_types/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./function_set_type"; 2 | -------------------------------------------------------------------------------- /src/util/arming.ts: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import fse from "fs-extra"; 3 | 4 | const findupSync = require("findup-sync"); 5 | 6 | function getDirIfIsFile(p: string): string { 7 | return fse.existsSync(p) && fse.statSync(p).isFile() ? path.dirname(p) : p; 8 | } 9 | 10 | export function getBasePath(paths: string[]): string { 11 | if (paths.length === 0) { 12 | throw new Error("Unable to detect base path for empty array of paths"); 13 | } 14 | 15 | let base: string; 16 | 17 | if (paths.length === 1) { 18 | base = paths[0]; 19 | } else { 20 | base = paths.reduce((prev, cur) => { 21 | let i = 0; 22 | 23 | while (prev[i] === cur[i]) { 24 | i++; 25 | } 26 | 27 | return prev.slice(0, i); 28 | }); 29 | } 30 | 31 | return getDirIfIsFile(base); 32 | } 33 | 34 | /** 35 | * @see https://ethereum.org/en/developers/docs/frameworks/ 36 | */ 37 | const possibleProjectRootFiles = [ 38 | "package.json", 39 | "brownie-config.yaml", 40 | "truffle-config.js", 41 | "hardhat.config.js", 42 | "embark.json", 43 | 44 | /** 45 | * Legacy or custom cases with lower priority 46 | */ 47 | "truffle.js" 48 | ]; 49 | 50 | export function detectProjectRoot(paths: string[]): string | undefined { 51 | const base = getBasePath(paths); 52 | const file = findupSync(possibleProjectRootFiles, { cwd: base }); 53 | 54 | return file === null ? undefined : path.dirname(file); 55 | } 56 | -------------------------------------------------------------------------------- /src/util/errors.ts: -------------------------------------------------------------------------------- 1 | import { Range } from "./location"; 2 | 3 | export class PPAbleError extends Error { 4 | readonly range: Range; 5 | constructor(msg: string, range: Range) { 6 | super(msg); 7 | this.range = range; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/util/fs.ts: -------------------------------------------------------------------------------- 1 | import fse from "fs-extra"; 2 | import path from "path"; 3 | 4 | export function searchRecursive(targetPath: string, filter: (entry: string) => boolean): string[] { 5 | const stat = fse.statSync(targetPath); 6 | const results: string[] = []; 7 | 8 | if (stat.isFile()) { 9 | results.push(path.resolve(targetPath)); 10 | 11 | return results; 12 | } 13 | 14 | for (const entry of fse.readdirSync(targetPath)) { 15 | const resolvedEntry = path.resolve(targetPath, entry); 16 | const stat = fse.statSync(resolvedEntry); 17 | 18 | if (stat.isDirectory()) { 19 | results.push(...searchRecursive(resolvedEntry, filter)); 20 | } else if (stat.isFile() && filter(resolvedEntry)) { 21 | results.push(resolvedEntry); 22 | } 23 | } 24 | 25 | return results; 26 | } 27 | -------------------------------------------------------------------------------- /src/util/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./fs"; 2 | export * from "./misc"; 3 | export * from "./set"; 4 | export * from "./json_output"; 5 | export * from "./arming"; 6 | export * from "./location"; 7 | export * from "./sources"; 8 | export * from "./errors"; 9 | export * from "./unicode"; 10 | -------------------------------------------------------------------------------- /src/util/name_generator.ts: -------------------------------------------------------------------------------- 1 | export class NameGenerator { 2 | private counters: { [base: string]: number }; 3 | private existingNames: Set; 4 | 5 | constructor(existingNames: Set) { 6 | this.counters = {}; 7 | this.existingNames = existingNames; 8 | } 9 | 10 | /** 11 | * Get a fresh name `${prefix}[0-9]+`. The returned name 12 | * will not collide with any of the names in `this.existingNames` or any 13 | * previous names returned by this function/ 14 | * 15 | * @param prefix 16 | * @param skipIdxOnFirst - if true, given a prefix `foo` it generates the sequence [`foo`, `foo1`, ...] instead of [`foo0`, `foo1`, ...] 17 | */ 18 | getFresh(prefix: string, skipIdxOnFirst = false): string { 19 | if (!(prefix in this.counters)) { 20 | if (skipIdxOnFirst) { 21 | this.counters[prefix] = 1; 22 | 23 | if (!this.existingNames.has(prefix)) { 24 | return prefix; 25 | } 26 | } else { 27 | this.counters[prefix] = 0; 28 | } 29 | } 30 | 31 | let res: string; 32 | 33 | do { 34 | res = prefix + this.counters[prefix]++; 35 | } while (this.existingNames.has(res)); 36 | 37 | return res; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/util/set.ts: -------------------------------------------------------------------------------- 1 | export function intersection(a: Set, b: Set): Set { 2 | const res: Set = new Set(); 3 | a.forEach((el) => { 4 | if (b.has(el)) res.add(el); 5 | }); 6 | return res; 7 | } 8 | 9 | export function union(a: Set, b: Set): Set { 10 | const res: Set = new Set(); 11 | a.forEach((el) => res.add(el)); 12 | b.forEach((el) => res.add(el)); 13 | return res; 14 | } 15 | -------------------------------------------------------------------------------- /src/util/sources.ts: -------------------------------------------------------------------------------- 1 | import { bytesToString } from "solc-typed-ast"; 2 | 3 | export abstract class SourceFile { 4 | public readonly contents; 5 | constructor( 6 | public fileName: string, 7 | public rawContents: Uint8Array 8 | ) { 9 | this.contents = bytesToString(rawContents); 10 | } 11 | } 12 | 13 | export class SolFile extends SourceFile {} 14 | export class MacroFile extends SourceFile {} 15 | 16 | export class UtilsSolFile extends SourceFile { 17 | constructor(fileName: string) { 18 | super(fileName, new Uint8Array()); 19 | } 20 | } 21 | 22 | export class DummySourceFile extends SourceFile { 23 | constructor() { 24 | super("", new Uint8Array()); 25 | } 26 | } 27 | 28 | export type SourceMap = Map; 29 | -------------------------------------------------------------------------------- /src/util/unicode.ts: -------------------------------------------------------------------------------- 1 | export type IdxToOffMap = Map; 2 | 3 | const utf8Enc = new TextEncoder(); 4 | const scratch = new Uint8Array(4); 5 | 6 | /** 7 | * Build a map from UTF-16 encoded string indices to their byte offsets in the 8 | * corresponding UTF-8 encoding. 9 | */ 10 | export function makeIdxToOffMap(s: string): IdxToOffMap { 11 | const res: IdxToOffMap = new Map(); 12 | let i = 0, 13 | off = 0; 14 | 15 | for (const ch of s) { 16 | res.set(i, off); 17 | const charBytes = utf8Enc.encodeInto(ch, scratch).written; 18 | 19 | i += charBytes <= 2 ? 1 : 2; 20 | off += charBytes; 21 | } 22 | 23 | res.set(i, off); 24 | 25 | return res; 26 | } 27 | 28 | export function isASCII(str: string): boolean { 29 | // eslint-disable-next-line no-control-regex 30 | return /^[\x00-\x7F]*$/.test(str); 31 | } 32 | -------------------------------------------------------------------------------- /static/annotated_badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ConsenSysDiligence/scribble/8fef54864fa77527825714eab26d50b7823be4fa/static/annotated_badge.png -------------------------------------------------------------------------------- /static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ConsenSysDiligence/scribble/8fef54864fa77527825714eab26d50b7823be4fa/static/logo.png -------------------------------------------------------------------------------- /stdlib/erc1155.scribble.yaml: -------------------------------------------------------------------------------- 1 | erc1155: 2 | variables: 3 | properties: 4 | safeTransferFrom(from, to, tokenId, value, data): 5 | - msg: "Cannot transfer to 0 address" 6 | prop: "#if_succeeds to != address(0);" 7 | - msg: "sender must have sufficient balance" 8 | prop: "#if_succeeds old(balanceOf(from, tokenId)) >= value;" 9 | - msg: "Sender must be properly authorized to transfer" 10 | prop: "#if_succeeds msg.sender == from || old(isApprovedForAll(from, msg.sender));" 11 | - msg: "Sender lost value tokens" 12 | prop: "#if_succeeds from != to ==> balanceOf(from, tokenId) == old(balanceOf(from, tokenId)) - value;" 13 | - msg: "Recipient gained value tokens (assuming non-deflationary tokens)" 14 | prop: "#if_succeeds from != to ==> balanceOf(to, tokenId) == old(balanceOf(to, tokenId)) + value;" 15 | safeBatchTransferFrom(from, to, ids, values, data): 16 | - msg: "Cannot transfer to 0 address" 17 | prop: "#if_succeeds to != address(0);" 18 | - msg: "Ids and values must have equal length" 19 | prop: "#if_succeeds values.length == ids.length;" 20 | - msg: "sender must have sufficient balance" 21 | prop: "#if_succeeds old(forall(uint i in ids) balanceOf(from, ids[i]) >= values[i]);" 22 | - msg: "Sender must be properly authorized to transfer" 23 | prop: "#if_succeeds msg.sender == from || old(isApprovedForAll(from, msg.sender));" 24 | setApprovalForAll(operator, approved): 25 | - msg: "setApprovalForAll worked correctly" 26 | prop: "#if_succeeds approved == isApprovedForAll(msg.sender, operator);" 27 | -------------------------------------------------------------------------------- /stdlib/ownable.scribble.yaml: -------------------------------------------------------------------------------- 1 | ownable: 2 | variables: 3 | _owner: address 4 | properties: 5 | _owner: 6 | - msg: "can only be updated by an owner" 7 | prop: "#if_updated old(_owner) == msg.sender;" 8 | -------------------------------------------------------------------------------- /test/integration/artefacts.spec.ts: -------------------------------------------------------------------------------- 1 | import expect from "expect"; 2 | import fse from "fs-extra"; 3 | import { searchRecursive } from "../../src"; 4 | import { makeArtefact, removeProcWd, toAst } from "./utils"; 5 | 6 | describe("Artefacts validation", () => { 7 | const samplesDir = "test/samples/"; 8 | const samples = searchRecursive(samplesDir, (fileName) => 9 | fileName.endsWith(".instrumented.sol") 10 | ).map((fileName) => removeProcWd(fileName).replace(".instrumented.sol", ".sol")); 11 | 12 | it(`Source samples are present in ${samplesDir}`, () => { 13 | expect(samples.length).toBeGreaterThan(0); 14 | }); 15 | 16 | for (const sample of samples) { 17 | const artefact = sample + ".json"; 18 | 19 | if (!fse.existsSync(artefact)) { 20 | continue; 21 | } 22 | 23 | it(`Artefact ${artefact} is up-to-date with ${sample}`, async () => { 24 | const expected = makeArtefact(await toAst(sample)); 25 | 26 | // Uncomment next line to update all of the artefacts 27 | // fse.writeFileSync(artefact, expected); 28 | 29 | const stored = fse.readFileSync(artefact, { encoding: "utf-8" }); 30 | 31 | expect(stored).toEqual(expected); 32 | }); 33 | } 34 | }); 35 | -------------------------------------------------------------------------------- /test/integration/scribble/_.spec.ts: -------------------------------------------------------------------------------- 1 | import { spawnSync } from "child_process"; 2 | import expect from "expect"; 3 | import fse from "fs-extra"; 4 | 5 | const cli = fse.readJSONSync("./src/bin/scribble_cli.json"); 6 | 7 | describe('Command "scribble" is working properly', () => { 8 | let exitCode: number | null; 9 | let outData: string; 10 | let errData: string; 11 | 12 | before(() => { 13 | const result = spawnSync("scribble", [], { encoding: "utf8" }); 14 | 15 | outData = result.stdout; 16 | errData = result.stderr; 17 | exitCode = result.status; 18 | }); 19 | 20 | describe("Command executed successfully", () => { 21 | it("Exit code is valid", () => { 22 | expect(exitCode).toEqual(0); 23 | }); 24 | 25 | it("STDERR is empty", () => { 26 | expect(errData).toEqual(""); 27 | }); 28 | }); 29 | 30 | describe("Software definition section", () => { 31 | const section = cli[0]; 32 | 33 | it("Output contains header", () => { 34 | expect(outData).toContain(section.header); 35 | }); 36 | 37 | it("Output contains description", () => { 38 | expect(outData).toContain(section.content); 39 | }); 40 | }); 41 | 42 | describe("Options description section", () => { 43 | const section = cli[1]; 44 | 45 | it("Output contains header", () => { 46 | expect(outData).toContain(section.header); 47 | }); 48 | 49 | for (const option of section.optionList) { 50 | if (option.alias) { 51 | it(`Output contains option "--${option.name}" with alias "-${option.alias}"`, () => { 52 | expect(outData).toContain(` --${option.name} `); 53 | expect(outData).toContain(` -${option.alias},`); 54 | }); 55 | } else { 56 | it(`Output contains option "--${option.name}"`, () => { 57 | expect(outData).toContain(` --${option.name} `); 58 | }); 59 | } 60 | } 61 | }); 62 | }); 63 | -------------------------------------------------------------------------------- /test/integration/scribble/download_compilers.spec.ts: -------------------------------------------------------------------------------- 1 | import { spawnSync } from "child_process"; 2 | import expect from "expect"; 3 | 4 | describe('Command "scribble --download-compilers native wasm" is working properly', () => { 5 | let exitCode: number | null; 6 | let outData: string; 7 | let errData: string; 8 | 9 | before(() => { 10 | const result = spawnSync("scribble", ["--download-compilers", "native", "wasm"], { 11 | encoding: "utf8" 12 | }); 13 | 14 | outData = result.stdout; 15 | errData = result.stderr; 16 | exitCode = result.status; 17 | }); 18 | 19 | it("Exit code is valid", () => { 20 | expect(exitCode).toEqual(0); 21 | }); 22 | 23 | it("STDERR is empty", () => { 24 | expect(errData).toEqual(""); 25 | }); 26 | 27 | it("STDOUT is correct", () => { 28 | const lines = outData.trimEnd().split("\n"); 29 | const header = lines.shift(); 30 | 31 | expect(header).toEqual("Downloading compilers (native, wasm) to current compiler cache:"); 32 | 33 | for (const line of lines) { 34 | expect(line).toMatch(/\((NativeCompiler|WasmCompiler) v\d+\.\d+\.\d+\)$/); 35 | } 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /test/integration/scribble/version.spec.ts: -------------------------------------------------------------------------------- 1 | import { spawnSync } from "child_process"; 2 | import expect from "expect"; 3 | 4 | describe('Command "scribble --version" is working properly', () => { 5 | let exitCode: number | null; 6 | let outData: string; 7 | let errData: string; 8 | 9 | before(() => { 10 | const result = spawnSync("scribble", ["--version"], { encoding: "utf8" }); 11 | 12 | outData = result.stdout; 13 | errData = result.stderr; 14 | exitCode = result.status; 15 | }); 16 | 17 | it("Exit code is valid", () => { 18 | expect(exitCode).toEqual(0); 19 | }); 20 | 21 | it("STDERR is empty", () => { 22 | expect(errData).toEqual(""); 23 | }); 24 | 25 | it("STDOUT is correct", () => { 26 | expect(outData).toMatch(/\d+.\d+.\d+/); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /test/integration/vm.spec.ts: -------------------------------------------------------------------------------- 1 | import fse from "fs-extra"; 2 | import path from "path"; 3 | import { executeTestSuite } from "./vm"; 4 | 5 | describe("VM", async () => { 6 | const directory = "test/samples/vm/"; 7 | const suites = fse.readdirSync(directory).filter((name) => name.endsWith(".vm.json")); 8 | 9 | for (const suite of suites) { 10 | const fileName = path.join(directory, suite); 11 | const config = fse.readJsonSync(fileName); 12 | 13 | await executeTestSuite(suite, config); 14 | } 15 | }); 16 | -------------------------------------------------------------------------------- /test/multifile_samples/arr_sum/main.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.4; 2 | 3 | contract Foo { 4 | // Simple map 5 | uint[] a = [10]; 6 | int8[] b; 7 | 8 | /// #if_succeeds unchecked_sum(a) > 10 && unchecked_sum(a) < 20; 9 | function pushA(uint k) public { 10 | a.push(k); 11 | } 12 | 13 | /// #if_succeeds unchecked_sum(a) > 10 && unchecked_sum(a) < 20; 14 | function setA(uint k, uint v) public { 15 | a[k] = v; 16 | } 17 | 18 | /// #if_succeeds unchecked_sum(b) > -10 && unchecked_sum(b) < 10; 19 | function pushB(int8 k) public { 20 | b.push(k); 21 | } 22 | 23 | /// #if_succeeds unchecked_sum(b) > -10 && unchecked_sum(b) < 10; 24 | function setB(uint k, int8 v) public { 25 | b[k] = v; 26 | } 27 | 28 | 29 | /// #if_succeeds unchecked_sum(c) > -10 && unchecked_sum(c) < 10; 30 | function memArr(int16[] memory c) public { 31 | } 32 | 33 | /// #if_succeeds unchecked_sum(c) > -10 && unchecked_sum(c) < 10; 34 | function calldataArr(int16[] calldata c) external { 35 | } 36 | 37 | /// #if_succeeds unchecked_sum(c) < 10; 38 | function overflowCheck(uint[] calldata c) external { 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /test/multifile_samples/asserts/A.sol: -------------------------------------------------------------------------------- 1 | uint constant X = 2; 2 | 3 | struct Point { 4 | uint x; 5 | uint y; 6 | } 7 | 8 | function foo(Point memory p) pure returns (uint) { 9 | return p.x + p.y; 10 | } -------------------------------------------------------------------------------- /test/multifile_samples/asserts/B.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.7; 2 | import "./A.sol"; 3 | 4 | /// #invariant sum < 200; 5 | contract Base { 6 | /// #if_updated sum - old(sum) > X+1; 7 | uint sum; 8 | 9 | /// #if_succeeds n.length < 10; 10 | function main(uint[] memory n) public { 11 | /// #assert forall (uint i in n) n[i] <= 50; 12 | for (uint i = 0; i < n.length; i++) { 13 | /// #assert n[i] > X; 14 | sum += n[i]; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /test/multifile_samples/asserts/C.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.7; 2 | import {X as XA} from "./A.sol"; 3 | import "./A.sol" as A; 4 | import "./B.sol" as B; 5 | import {X as XB} from "./B.sol"; 6 | 7 | contract Child is B.Base { 8 | function main1(uint t) public { 9 | /// #assert XA == 2 && XB == 2 && A.X == 2 && B.X == 2 && t == B.X; 10 | t++; 11 | 12 | A.Point memory p; 13 | p.x = 1; 14 | p.y = 2; 15 | /// #assert B.foo(p) == 3; 16 | t++; 17 | } 18 | } -------------------------------------------------------------------------------- /test/multifile_samples/circular_imports/A.sol: -------------------------------------------------------------------------------- 1 | import "./B.sol"; 2 | 3 | /// #invariant true; 4 | contract A { 5 | function a(B b) external returns (B) { return b; } 6 | } 7 | -------------------------------------------------------------------------------- /test/multifile_samples/circular_imports/B.sol: -------------------------------------------------------------------------------- 1 | import "./A.sol"; 2 | 3 | /// #invariant true; 4 | contract B { 5 | function a(A a) external returns (A) { return a; } 6 | } 7 | -------------------------------------------------------------------------------- /test/multifile_samples/custom_operators/operators.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.19; 2 | 3 | type Custom is uint256; 4 | 5 | function plus(Custom a, Custom b) pure returns (Custom) { 6 | return Custom.wrap(Custom.unwrap(a) + Custom.unwrap(b)); 7 | } 8 | 9 | function diff(Custom a, Custom b) pure returns (Custom) { 10 | return Custom.wrap(Custom.unwrap(a) - Custom.unwrap(b)); 11 | } 12 | 13 | function eq(Custom a, Custom b) pure returns (bool) { 14 | return Custom.unwrap(a) == Custom.unwrap(b); 15 | } 16 | 17 | using { plus as +, diff as -, eq as == } for Custom global; 18 | -------------------------------------------------------------------------------- /test/multifile_samples/custom_operators/sample.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.19; 2 | 3 | import "./operators.sol"; 4 | 5 | contract Test { 6 | Custom a; 7 | Custom b; 8 | 9 | /// #if_succeeds true; 10 | function main() public { 11 | Custom a = Custom.wrap(1); 12 | Custom b = Custom.wrap(2); 13 | 14 | a + b; 15 | a - b; 16 | a == b; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/multifile_samples/erc20_macro_inheritance/child.sol: -------------------------------------------------------------------------------- 1 | import "./erc20_base.sol"; 2 | /** 3 | * #macro erc20(balances, allowances, _totalSupply); 4 | */ 5 | contract Token is ERC20 { 6 | constructor() public ERC20(100000) { 7 | } 8 | 9 | function allowance(address owner, address delegate) public override view returns (uint) { 10 | return ERC20.allowance(owner, delegate); 11 | } 12 | } -------------------------------------------------------------------------------- /test/multifile_samples/forall_maps/base.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.4; 2 | 3 | contract Base { 4 | // Simple map 5 | mapping(uint => uint) a; 6 | 7 | // Map with complex key 8 | mapping (string => int16) public c; 9 | 10 | string sS; 11 | 12 | // Nested map 13 | mapping (string => mapping(uint8 => int8)) d; 14 | 15 | // Map to array forall 16 | mapping (uint => uint[]) e; 17 | 18 | // Array of maps, array forall only 19 | mapping (uint => uint)[] f; 20 | 21 | // Array of maps, map forall only 22 | mapping (uint => uint)[] g; 23 | 24 | // Nested map first map only 25 | mapping (string => mapping(uint8 => int8)) h; 26 | 27 | // Nested map last map only 28 | mapping (string => mapping(uint8 => int8)) i; 29 | 30 | struct SA { 31 | mapping(string=>uint) m; 32 | uint cnt; 33 | } 34 | 35 | struct SB { 36 | SA[] sas; 37 | } 38 | 39 | SB j; 40 | } 41 | -------------------------------------------------------------------------------- /test/multifile_samples/import_file_level_fn_and_var/A.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.7.0; 2 | 3 | uint constant SOME = 10; 4 | 5 | function addSome(uint v) pure returns (uint) { 6 | return v + SOME; 7 | } 8 | -------------------------------------------------------------------------------- /test/multifile_samples/import_file_level_fn_and_var/B.sol: -------------------------------------------------------------------------------- 1 | import "./A.sol" as A; 2 | -------------------------------------------------------------------------------- /test/multifile_samples/import_file_level_fn_and_var/C.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.7.0; 2 | 3 | import {SOME as OTHER, addSome as addOther} from "./A.sol"; 4 | import "./A.sol" as A; 5 | import "./B.sol" as B; 6 | import {A as X} from "./B.sol"; 7 | 8 | contract Test { 9 | uint num = A.SOME; 10 | 11 | /// #if_succeeds {:msg "P1"} num == 35; 12 | function one() public { 13 | num = addOther(15 + OTHER); 14 | } 15 | 16 | /// #if_succeeds {:msg "P2"} num == 35; 17 | function two() public { 18 | num = A.addSome(15 + A.SOME); 19 | } 20 | 21 | /// #if_succeeds {:msg "P3"} num == 35; 22 | function three() public { 23 | num = B.A.addSome(15 + B.A.SOME); 24 | } 25 | 26 | /// #if_succeeds {:msg "P4"} num == 35; 27 | function four() public { 28 | num = X.addSome(15 + X.SOME); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /test/multifile_samples/import_rewrites/flat.sol.expected: -------------------------------------------------------------------------------- 1 | /// This file is auto-generated by Scribble and shouldn't be edited directly. 2 | /// Use --disarm prior to make any changes. 3 | pragma solidity 0.6.11; 4 | 5 | enum Enum1 { 6 | A, 7 | B, 8 | C 9 | } 10 | 11 | enum Enum2 { 12 | E, 13 | F, 14 | G 15 | } 16 | 17 | enum Struct1_1 { 18 | H, 19 | I, 20 | J 21 | } 22 | 23 | struct Struct1 { 24 | uint256 x; 25 | } 26 | 27 | contract Imp1 {} 28 | 29 | contract Foo is Imp1 { 30 | Struct1 internal s; 31 | Enum1 internal e1; 32 | Enum2 internal fe; 33 | Struct1_1 internal e3; 34 | } -------------------------------------------------------------------------------- /test/multifile_samples/import_rewrites/imp1.sol: -------------------------------------------------------------------------------- 1 | pragma solidity "0.6.11"; 2 | import { Struct1 } from "./imp2.sol"; 3 | import { Enum1 } from "./imp3.sol"; 4 | import { Enum2 as FooEnum, Struct1 as Enum3 } from "./imp3.sol"; 5 | 6 | contract Imp1 {} 7 | -------------------------------------------------------------------------------- /test/multifile_samples/import_rewrites/imp2.sol: -------------------------------------------------------------------------------- 1 | pragma solidity "0.6.11"; 2 | 3 | struct Struct1 { 4 | uint256 x; 5 | } 6 | -------------------------------------------------------------------------------- /test/multifile_samples/import_rewrites/imp3.sol: -------------------------------------------------------------------------------- 1 | pragma solidity "0.6.11"; 2 | 3 | enum Enum1 { A, B, C } 4 | 5 | enum Enum2 { E, F, G } 6 | 7 | enum Struct1 { H, I, J } 8 | -------------------------------------------------------------------------------- /test/multifile_samples/import_rewrites/main.sol: -------------------------------------------------------------------------------- 1 | pragma solidity "0.6.11"; 2 | import "./imp1.sol"; 3 | 4 | contract Foo is Imp1 { 5 | Struct1 s; 6 | Enum1 e1; 7 | FooEnum fe; 8 | Enum3 e3; 9 | } 10 | -------------------------------------------------------------------------------- /test/multifile_samples/inheritance1/A.sol: -------------------------------------------------------------------------------- 1 | contract A { 2 | 3 | /// #if_succeeds $result >= x; 4 | function foo(uint x) public virtual returns (uint) { 5 | return x+1; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/multifile_samples/inheritance1/B.sol: -------------------------------------------------------------------------------- 1 | contract B { 2 | } 3 | -------------------------------------------------------------------------------- /test/multifile_samples/inheritance1/C.sol: -------------------------------------------------------------------------------- 1 | import "./A.sol"; 2 | import "./B.sol"; 3 | /// #invariant {:msg "P1"} true; 4 | contract C is B, A { 5 | /// #if_succeeds $result >= x+2; 6 | function foo(uint x) public virtual override returns (uint) { 7 | return x+2; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/multifile_samples/inheritance1/D.sol: -------------------------------------------------------------------------------- 1 | import "./A.sol"; 2 | import "./B.sol"; 3 | contract D is B, A { } 4 | -------------------------------------------------------------------------------- /test/multifile_samples/macros/base.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.0; 3 | 4 | /** 5 | * #macro ownable(owner); 6 | */ 7 | contract Ownable { 8 | address public owner; 9 | 10 | event OwnershipTransferred(address indexed from, address indexed to); 11 | 12 | constructor() { 13 | transferOwnership(msg.sender); 14 | } 15 | 16 | modifier onlyOwner() { 17 | require(owner == msg.sender, "Ownable: message sender is not the current owner"); 18 | 19 | _; 20 | } 21 | 22 | function transferOwnership(address to) public virtual onlyOwner { 23 | address from = owner; 24 | 25 | owner = to; 26 | 27 | emit OwnershipTransferred(from, to); 28 | } 29 | } 30 | 31 | contract Test is Ownable {} 32 | -------------------------------------------------------------------------------- /test/multifile_samples/macros/child.sol: -------------------------------------------------------------------------------- 1 | import "./base.sol"; 2 | 3 | /// #macro macro2(); 4 | contract Foo { 5 | function foo(uint z, uint w) public {} 6 | } 7 | -------------------------------------------------------------------------------- /test/multifile_samples/macros/child.sol.instrumented.expected: -------------------------------------------------------------------------------- 1 | /// This file is auto-generated by Scribble and shouldn't be edited directly. 2 | /// Use --disarm prior to make any changes. 3 | import "./base.sol"; 4 | 5 | /// #macro macro2(); 6 | contract Foo { 7 | function foo(uint z, uint w) public { 8 | _original_Foo_foo(z, w); 9 | unchecked { 10 | if (!((z + w) > 0)) { 11 | emit __ScribbleUtilsLib__69.AssertionFailed("000325:0071:001 3: dummy"); 12 | assert(false); 13 | } 14 | } 15 | } 16 | 17 | function _original_Foo_foo(uint z, uint w) internal {} 18 | } 19 | 20 | library __ScribbleUtilsLib__69 { 21 | event AssertionFailed(string message); 22 | 23 | event AssertionFailedData(int eventId, bytes encodingData); 24 | 25 | function assertionFailed(string memory arg_0) internal { 26 | emit AssertionFailed(arg_0); 27 | } 28 | 29 | function assertionFailedData(int arg_0, bytes memory arg_1) internal { 30 | emit AssertionFailedData(arg_0, arg_1); 31 | } 32 | 33 | function isInContract() internal returns (bool res) { 34 | assembly { 35 | res := sload(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c) 36 | } 37 | } 38 | 39 | function setInContract(bool v) internal { 40 | assembly { 41 | sstore(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c, v) 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /test/multifile_samples/macros/macro1.scribble.yaml: -------------------------------------------------------------------------------- 1 | ownable: 2 | variables: 3 | _owner: address 4 | properties: 5 | _owner: 6 | - msg: "can only be updated by an owner" 7 | prop: "#if_updated old(_owner) == msg.sender;" 8 | -------------------------------------------------------------------------------- /test/multifile_samples/macros/macro2.scribble.yaml: -------------------------------------------------------------------------------- 1 | macro2: 2 | variables: 3 | properties: 4 | "foo(x, y)": 5 | - msg: "dummy" 6 | prop: "#if_succeeds x + y > 0;" 7 | -------------------------------------------------------------------------------- /test/multifile_samples/node_modules_erc20/contracts/Foo.sol: -------------------------------------------------------------------------------- 1 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 2 | 3 | /// #invariant true; 4 | abstract contract Foo is ERC20 { 5 | } 6 | -------------------------------------------------------------------------------- /test/multifile_samples/node_modules_erc20/contracts/Foo.sol.instrumented.expected: -------------------------------------------------------------------------------- 1 | /// This file is auto-generated by Scribble and shouldn't be edited directly. 2 | /// Use --disarm prior to make any changes. 3 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 4 | 5 | /// #invariant true; 6 | abstract contract Foo is ERC20 { 7 | /// Check only the current contract's state invariants 8 | function __scribble_Foo_check_state_invariants_internal() internal { 9 | unchecked { 10 | if (!(true)) { 11 | emit __ScribbleUtilsLib__6.AssertionFailed("000428:0065:000 0: "); 12 | assert(false); 13 | } 14 | } 15 | } 16 | 17 | /// Check the state invariant for the current contract and all its bases 18 | function __scribble_check_state_invariants() virtual override internal { 19 | __scribble_Foo_check_state_invariants_internal(); 20 | __scribble_ERC20_check_state_invariants_internal(); 21 | __scribble_Context_check_state_invariants_internal(); 22 | } 23 | 24 | constructor() { 25 | __ScribbleUtilsLib__6.setInContract(true); 26 | __scribble_check_state_invariants(); 27 | __ScribbleUtilsLib__6.setInContract(false); 28 | } 29 | } 30 | 31 | library __ScribbleUtilsLib__6 { 32 | event AssertionFailed(string message); 33 | 34 | event AssertionFailedData(int eventId, bytes encodingData); 35 | 36 | function assertionFailed(string memory arg_0) internal { 37 | emit AssertionFailed(arg_0); 38 | } 39 | 40 | function assertionFailedData(int arg_0, bytes memory arg_1) internal { 41 | emit AssertionFailedData(arg_0, arg_1); 42 | } 43 | 44 | function isInContract() internal returns (bool res) { 45 | assembly { 46 | res := sload(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c) 47 | } 48 | } 49 | 50 | function setInContract(bool v) internal { 51 | assembly { 52 | sstore(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c, v) 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /test/multifile_samples/node_modules_erc20/node_modules/@openzeppelin/contracts/package.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ConsenSysDiligence/scribble/8fef54864fa77527825714eab26d50b7823be4fa/test/multifile_samples/node_modules_erc20/node_modules/@openzeppelin/contracts/package.json -------------------------------------------------------------------------------- /test/multifile_samples/node_modules_erc20/node_modules/@openzeppelin/contracts/utils/Context.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | /** 7 | * @dev Provides information about the current execution context, including the 8 | * sender of the transaction and its data. While these are generally available 9 | * via msg.sender and msg.data, they should not be accessed in such a direct 10 | * manner, since when dealing with meta-transactions the account sending and 11 | * paying for execution may not be the actual sender (as far as an application 12 | * is concerned). 13 | * 14 | * This contract is only required for intermediate, library-like contracts. 15 | */ 16 | abstract contract Context { 17 | function _msgSender() internal view virtual returns (address) { 18 | return msg.sender; 19 | } 20 | 21 | function _msgData() internal view virtual returns (bytes calldata) { 22 | return msg.data; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/multifile_samples/node_modules_erc20_2/contracts/Foo.sol: -------------------------------------------------------------------------------- 1 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 2 | 3 | /// #invariant true; 4 | abstract contract Foo is ERC20 { 5 | } 6 | -------------------------------------------------------------------------------- /test/multifile_samples/node_modules_erc20_2/contracts/Foo.sol.instrumented.expected: -------------------------------------------------------------------------------- 1 | /// This file is auto-generated by Scribble and shouldn't be edited directly. 2 | /// Use --disarm prior to make any changes. 3 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 4 | 5 | /// #invariant true; 6 | abstract contract Foo is ERC20 { 7 | /// Check only the current contract's state invariants 8 | function __scribble_Foo_check_state_invariants_internal() internal { 9 | unchecked { 10 | if (!(true)) { 11 | emit __ScribbleUtilsLib__685.AssertionFailed("000428:0067:002 0: "); 12 | assert(false); 13 | } 14 | } 15 | } 16 | 17 | /// Check the state invariant for the current contract and all its bases 18 | function __scribble_check_state_invariants() virtual override internal { 19 | __scribble_Foo_check_state_invariants_internal(); 20 | __scribble_ERC20_check_state_invariants_internal(); 21 | __scribble_Context_check_state_invariants_internal(); 22 | } 23 | 24 | constructor() { 25 | __ScribbleUtilsLib__685.setInContract(true); 26 | __scribble_check_state_invariants(); 27 | __ScribbleUtilsLib__685.setInContract(false); 28 | } 29 | } 30 | 31 | library __ScribbleUtilsLib__685 { 32 | event AssertionFailed(string message); 33 | 34 | event AssertionFailedData(int eventId, bytes encodingData); 35 | 36 | function assertionFailed(string memory arg_0) internal { 37 | emit AssertionFailed(arg_0); 38 | } 39 | 40 | function assertionFailedData(int arg_0, bytes memory arg_1) internal { 41 | emit AssertionFailedData(arg_0, arg_1); 42 | } 43 | 44 | function isInContract() internal returns (bool res) { 45 | assembly { 46 | res := sload(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c) 47 | } 48 | } 49 | 50 | function setInContract(bool v) internal { 51 | assembly { 52 | sstore(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c, v) 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /test/multifile_samples/node_modules_erc20_2/node_modules/@openzeppelin/contracts/package.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ConsenSysDiligence/scribble/8fef54864fa77527825714eab26d50b7823be4fa/test/multifile_samples/node_modules_erc20_2/node_modules/@openzeppelin/contracts/package.json -------------------------------------------------------------------------------- /test/multifile_samples/node_modules_erc20_2/node_modules/@openzeppelin/contracts/utils/Context.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | /** 7 | * @dev Provides information about the current execution context, including the 8 | * sender of the transaction and its data. While these are generally available 9 | * via msg.sender and msg.data, they should not be accessed in such a direct 10 | * manner, since when dealing with meta-transactions the account sending and 11 | * paying for execution may not be the actual sender (as far as an application 12 | * is concerned). 13 | * 14 | * This contract is only required for intermediate, library-like contracts. 15 | */ 16 | abstract contract Context { 17 | function _msgSender() internal view virtual returns (address) { 18 | return msg.sender; 19 | } 20 | 21 | function _msgData() internal view virtual returns (bytes calldata) { 22 | return msg.data; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/multifile_samples/node_modules_erc20_3/contracts/Foo.sol: -------------------------------------------------------------------------------- 1 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 2 | 3 | /// #invariant true; 4 | abstract contract Foo is ERC20 { 5 | } 6 | -------------------------------------------------------------------------------- /test/multifile_samples/node_modules_erc20_3/contracts/Foo.sol.instrumented.expected: -------------------------------------------------------------------------------- 1 | /// This file is auto-generated by Scribble and shouldn't be edited directly. 2 | /// Use --disarm prior to make any changes. 3 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 4 | 5 | /// #invariant true; 6 | abstract contract Foo is ERC20 { 7 | /// Check only the current contract's state invariants 8 | function __scribble_Foo_check_state_invariants_internal() internal { 9 | unchecked { 10 | if (!(true)) { 11 | emit __ScribbleUtilsLib__685.AssertionFailed("000428:0067:002 0: "); 12 | assert(false); 13 | } 14 | } 15 | } 16 | 17 | /// Check the state invariant for the current contract and all its bases 18 | function __scribble_check_state_invariants() virtual override internal { 19 | __scribble_Foo_check_state_invariants_internal(); 20 | __scribble_ERC20_check_state_invariants_internal(); 21 | __scribble_Context_check_state_invariants_internal(); 22 | } 23 | 24 | constructor() { 25 | __ScribbleUtilsLib__685.setInContract(true); 26 | __scribble_check_state_invariants(); 27 | __ScribbleUtilsLib__685.setInContract(false); 28 | } 29 | } 30 | 31 | library __ScribbleUtilsLib__685 { 32 | event AssertionFailed(string message); 33 | 34 | event AssertionFailedData(int eventId, bytes encodingData); 35 | 36 | function assertionFailed(string memory arg_0) internal { 37 | emit AssertionFailed(arg_0); 38 | } 39 | 40 | function assertionFailedData(int arg_0, bytes memory arg_1) internal { 41 | emit AssertionFailedData(arg_0, arg_1); 42 | } 43 | 44 | function isInContract() internal returns (bool res) { 45 | assembly { 46 | res := sload(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c) 47 | } 48 | } 49 | 50 | function setInContract(bool v) internal { 51 | assembly { 52 | sstore(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c, v) 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /test/multifile_samples/node_modules_erc20_3/node_modules/@openzeppelin/contracts/package.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ConsenSysDiligence/scribble/8fef54864fa77527825714eab26d50b7823be4fa/test/multifile_samples/node_modules_erc20_3/node_modules/@openzeppelin/contracts/package.json -------------------------------------------------------------------------------- /test/multifile_samples/node_modules_erc20_3/node_modules/@openzeppelin/contracts/utils/Context.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | /** 7 | * @dev Provides information about the current execution context, including the 8 | * sender of the transaction and its data. While these are generally available 9 | * via msg.sender and msg.data, they should not be accessed in such a direct 10 | * manner, since when dealing with meta-transactions the account sending and 11 | * paying for execution may not be the actual sender (as far as an application 12 | * is concerned). 13 | * 14 | * This contract is only required for intermediate, library-like contracts. 15 | */ 16 | abstract contract Context { 17 | function _msgSender() internal view virtual returns (address) { 18 | return msg.sender; 19 | } 20 | 21 | function _msgData() internal view virtual returns (bytes calldata) { 22 | return msg.data; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/multifile_samples/proj1/base.sol: -------------------------------------------------------------------------------- 1 | pragma solidity "0.6.11"; 2 | /// #invariant {:msg "P0"} x > 0; 3 | contract Base { 4 | uint x=1; 5 | } 6 | -------------------------------------------------------------------------------- /test/multifile_samples/proj1/base.sol.instrumented.expected: -------------------------------------------------------------------------------- 1 | /// This file is auto-generated by Scribble and shouldn't be edited directly. 2 | /// Use --disarm prior to make any changes. 3 | pragma solidity 0.6.11; 4 | 5 | /// #invariant {:msg "P0"} x > 0; 6 | contract Base { 7 | uint internal x = 1; 8 | 9 | /// Check only the current contract's state invariants 10 | function __scribble_Base_check_state_invariants_internal() internal { 11 | if (!(x > 0)) { 12 | emit __ScribbleUtilsLib__7.AssertionFailed("000392:0067:000 0: P0"); 13 | assert(false); 14 | } 15 | } 16 | 17 | /// Check the state invariant for the current contract and all its bases 18 | function __scribble_check_state_invariants() virtual internal { 19 | __scribble_Base_check_state_invariants_internal(); 20 | } 21 | 22 | constructor() public { 23 | __ScribbleUtilsLib__7.setInContract(true); 24 | __scribble_check_state_invariants(); 25 | __ScribbleUtilsLib__7.setInContract(false); 26 | } 27 | } 28 | 29 | library __ScribbleUtilsLib__7 { 30 | event AssertionFailed(string message); 31 | 32 | event AssertionFailedData(int eventId, bytes encodingData); 33 | 34 | function assertionFailed(string memory arg_0) internal { 35 | emit AssertionFailed(arg_0); 36 | } 37 | 38 | function assertionFailedData(int arg_0, bytes memory arg_1) internal { 39 | emit AssertionFailedData(arg_0, arg_1); 40 | } 41 | 42 | function isInContract() internal returns (bool res) { 43 | assembly { 44 | res := sload(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c) 45 | } 46 | } 47 | 48 | function setInContract(bool v) internal { 49 | assembly { 50 | sstore(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c, v) 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /test/multifile_samples/proj1/child1.sol: -------------------------------------------------------------------------------- 1 | pragma solidity "0.6.11"; 2 | import {Base} from "./base.sol"; 3 | contract Child1 is Base { 4 | /// #if_succeeds {:msg "P1"} x == old(x) + y; 5 | function add(uint y) public { 6 | x += y; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/multifile_samples/proj1/child2.sol: -------------------------------------------------------------------------------- 1 | pragma solidity "0.6.11"; 2 | import {Base} from "./base.sol"; 3 | contract Child2 is Base { 4 | /// #if_succeeds {:msg "P2"} x == 2* old(x); 5 | function double() public { 6 | x *= 2; 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /test/multifile_samples/reexported_imports/flat.sol.expected: -------------------------------------------------------------------------------- 1 | /// This file is auto-generated by Scribble and shouldn't be edited directly. 2 | /// Use --disarm prior to make any changes. 3 | pragma solidity 0.7.5; 4 | 5 | struct Foo { 6 | uint x; 7 | } 8 | 9 | contract Goo { 10 | Foo internal s3; 11 | Foo internal s4; 12 | Foo internal s5; 13 | } -------------------------------------------------------------------------------- /test/multifile_samples/reexported_imports/imp1.sol: -------------------------------------------------------------------------------- 1 | pragma solidity "0.7.5"; 2 | 3 | struct Foo { 4 | uint x; 5 | } 6 | -------------------------------------------------------------------------------- /test/multifile_samples/reexported_imports/imp2.sol: -------------------------------------------------------------------------------- 1 | pragma solidity "0.7.5"; 2 | 3 | import {Foo as Bar} from "./imp1.sol"; 4 | import "./imp1.sol" as I1; 5 | -------------------------------------------------------------------------------- /test/multifile_samples/reexported_imports/imp3.sol: -------------------------------------------------------------------------------- 1 | pragma solidity "0.7.5"; 2 | 3 | import {Bar as Boo, I1 as I1} from "./imp2.sol"; 4 | 5 | import "./imp2.sol" as I2; 6 | -------------------------------------------------------------------------------- /test/multifile_samples/reexported_imports/instrumentationMetadata.json.expected: -------------------------------------------------------------------------------- 1 | { 2 | "instrToOriginalMap": [ 3 | [ 4 | "146:26:0", 5 | "26:23:0" 6 | ], 7 | [ 8 | "163:6:0", 9 | "40:6:0" 10 | ], 11 | [ 12 | "163:4:0", 13 | "40:4:0" 14 | ], 15 | [ 16 | "174:79:0", 17 | "47:111:3" 18 | ], 19 | [ 20 | "193:15:0", 21 | "125:6:3" 22 | ], 23 | [ 24 | "193:3:0", 25 | "125:3:3" 26 | ], 27 | [ 28 | "214:15:0", 29 | "134:9:3" 30 | ], 31 | [ 32 | "214:3:0", 33 | "134:6:3" 34 | ], 35 | [ 36 | "235:15:0", 37 | "146:9:3" 38 | ], 39 | [ 40 | "235:3:0", 41 | "146:6:3" 42 | ] 43 | ], 44 | "otherInstrumentation": [], 45 | "propertyMap": [], 46 | "originalSourceList": [ 47 | "test/multifile_samples/reexported_imports/imp1.sol", 48 | "test/multifile_samples/reexported_imports/imp2.sol", 49 | "test/multifile_samples/reexported_imports/imp3.sol", 50 | "test/multifile_samples/reexported_imports/main.sol" 51 | ], 52 | "instrSourceList": [ 53 | "--" 54 | ], 55 | "scribbleVersion": "0.7.0" 56 | } -------------------------------------------------------------------------------- /test/multifile_samples/reexported_imports/main.sol: -------------------------------------------------------------------------------- 1 | pragma solidity "0.7.5"; 2 | import "./imp3.sol"; 3 | 4 | contract Goo { 5 | //Foo s1; Foo is not in scope 6 | //Bar s2; Bar is not in scope 7 | Boo s3; 8 | I2.Bar s4; 9 | I1.Foo s5; 10 | } 11 | -------------------------------------------------------------------------------- /test/multifile_samples/reexported_imports_05/flat.sol.expected: -------------------------------------------------------------------------------- 1 | /// This file is auto-generated by Scribble and shouldn't be edited directly. 2 | /// Use --disarm prior to make any changes. 3 | pragma solidity 0.5.0; 4 | 5 | contract Foo { 6 | uint internal x; 7 | 8 | function foo() public pure returns (uint) { 9 | return 1; 10 | } 11 | } 12 | 13 | contract Moo { 14 | uint internal y; 15 | } 16 | 17 | contract Goo is Foo { 18 | Foo internal s3; 19 | Foo internal s4; 20 | Foo internal s5; 21 | 22 | function baz() public pure returns (uint) { 23 | return Foo.foo(); 24 | } 25 | 26 | function main() public { 27 | Foo x = new Foo(); 28 | Foo y = new Foo(); 29 | Foo z = new Foo(); 30 | Moo w = new Moo(); 31 | function() internal pure returns (uint) f = Foo.foo; 32 | uint t = Foo.x; 33 | uint t1 = Foo.x; 34 | } 35 | } -------------------------------------------------------------------------------- /test/multifile_samples/reexported_imports_05/imp1.sol: -------------------------------------------------------------------------------- 1 | pragma solidity "0.5.0"; 2 | 3 | contract Foo { 4 | uint x; 5 | 6 | function foo() public pure returns (uint) { 7 | return 1; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/multifile_samples/reexported_imports_05/imp2.sol: -------------------------------------------------------------------------------- 1 | pragma solidity "0.5.0"; 2 | 3 | import {Foo as Bar} from "./imp1.sol"; 4 | import "./imp1.sol" as I1; 5 | -------------------------------------------------------------------------------- /test/multifile_samples/reexported_imports_05/imp3.sol: -------------------------------------------------------------------------------- 1 | pragma solidity "0.5.0"; 2 | 3 | import {Bar as Boo, I1 as I11} from "./imp2.sol"; 4 | 5 | import "./imp2.sol" as I2; 6 | 7 | contract Moo { 8 | uint y; 9 | } 10 | -------------------------------------------------------------------------------- /test/multifile_samples/reexported_imports_05/main.sol: -------------------------------------------------------------------------------- 1 | pragma solidity "0.5.0"; 2 | import "./imp3.sol"; 3 | import "./imp3.sol" as I3; 4 | 5 | contract Goo is I11.Foo { 6 | //Foo s1; Foo is not in scope 7 | //Bar s2; Bar is not in scope 8 | Boo s3; 9 | I2.Bar s4; 10 | I11.Foo s5; 11 | 12 | function baz() public pure returns (uint) { 13 | return I11.Foo.foo(); 14 | } 15 | 16 | function main() public { 17 | Boo x = new Boo(); 18 | I2.Bar y = new I2.Bar(); 19 | I11.Foo z = new I11.Foo(); 20 | 21 | I3.Moo w = new I3.Moo(); 22 | 23 | function() pure returns (uint) f = I11.Foo.foo; 24 | uint t = I11.Foo.x; 25 | uint t1 = Boo.x; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/multifile_samples/using_for_free_funcs/flat.sol.expected: -------------------------------------------------------------------------------- 1 | /// This file is auto-generated by Scribble and shouldn't be edited directly. 2 | /// Use --disarm prior to make any changes. 3 | pragma solidity 0.8.13; 4 | 5 | type Y is address; 6 | 7 | type X is uint256; 8 | 9 | type Y_1 is bool; 10 | 11 | using { add_1 } for X global; 12 | 13 | function zerroAddr() returns (Y) { 14 | return Y.wrap(address(0x0)); 15 | } 16 | 17 | function add(X a, X b) pure returns (uint256) { 18 | return 1; 19 | } 20 | 21 | function not(Y_1 x) returns (Y_1) { 22 | return Y_1.wrap(!Y_1.unwrap(x)); 23 | } 24 | 25 | function add_1(X a, X b) pure returns (X) { 26 | return X.wrap(X.unwrap(a) + X.unwrap(b)); 27 | } 28 | 29 | contract Test { 30 | function main() public returns (X RET_0) { 31 | RET_0 = _original_Test_main(); 32 | unchecked { 33 | if (!(true)) { 34 | emit __ScribbleUtilsLib__65.AssertionFailed("000707:0066:000 0: "); 35 | assert(false); 36 | } 37 | } 38 | } 39 | 40 | function _original_Test_main() internal returns (X) { 41 | X a = X.wrap(1); 42 | X b = X.wrap(2); 43 | return a.add_1(b); 44 | } 45 | } 46 | 47 | library __ScribbleUtilsLib__65 { 48 | event AssertionFailed(string message); 49 | 50 | event AssertionFailedData(int eventId, bytes encodingData); 51 | 52 | function assertionFailed(string memory arg_0) internal { 53 | emit AssertionFailed(arg_0); 54 | } 55 | 56 | function assertionFailedData(int arg_0, bytes memory arg_1) internal { 57 | emit AssertionFailedData(arg_0, arg_1); 58 | } 59 | 60 | function isInContract() internal returns (bool res) { 61 | assembly { 62 | res := sload(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c) 63 | } 64 | } 65 | 66 | function setInContract(bool v) internal { 67 | assembly { 68 | sstore(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c, v) 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /test/multifile_samples/using_for_free_funcs/sample.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.13; 2 | 3 | import { X } from "./util.sol"; 4 | 5 | type Y is address; 6 | 7 | function zerroAddr() returns (Y) { 8 | return Y.wrap(address(0x0)); 9 | } 10 | 11 | function add(X a, X b) pure returns (uint256) { 12 | return 1; 13 | } 14 | 15 | contract Test { 16 | /// #if_succeeds true; 17 | function main() public returns (X) { 18 | X a = X.wrap(1); 19 | X b = X.wrap(2); 20 | 21 | return a.add(b); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/multifile_samples/using_for_free_funcs/util.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.13; 2 | 3 | type X is uint256; 4 | type Y is bool; 5 | 6 | function not(Y x) returns (Y) { 7 | return Y.wrap(!Y.unwrap(x)); 8 | } 9 | 10 | function add(X a, X b) pure returns (X) { 11 | return X.wrap(X.unwrap(a) + X.unwrap(b)); 12 | } 13 | 14 | using { add } for X global; 15 | -------------------------------------------------------------------------------- /test/samples/SimpleStorage.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.2; 2 | 3 | contract SimpleStorage { 4 | uint storedData; 5 | 6 | event Notification(uint val, string message); 7 | 8 | constructor(uint data) public { 9 | storedData = data; 10 | } 11 | 12 | function set(uint x) public returns (uint) { 13 | storedData = x; 14 | 15 | emit Notification(x, "set"); 16 | 17 | return storedData; 18 | } 19 | 20 | function get() public view returns (uint) { 21 | return storedData; 22 | } 23 | 24 | function fail() public pure { 25 | assert(false); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/samples/calldata_parameters.pre_0.6.9.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.6.8; 2 | /// #invariant {:msg "P1"} true; 3 | contract Test { 4 | function foo(bytes calldata x) external returns (uint) { 5 | return x.length; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/samples/calldata_paramteres.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.6.10; 2 | /// #invariant {:msg "P1"} true; 3 | contract Test { 4 | function foo(bytes calldata x) external returns (bytes calldata y) { 5 | y = x; 6 | } 7 | 8 | function moo() public { 9 | bytes memory m = "abc"; 10 | bytes memory n = this.foo(m); 11 | 12 | assert(n[0] == "a"); 13 | assert(n[1] == "b"); 14 | assert(n[2] == "c"); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/samples/cha.sol: -------------------------------------------------------------------------------- 1 | type Custom is uint256; 2 | 3 | function plus(Custom a, Custom b) pure returns (Custom) { 4 | return Custom.wrap(Custom.unwrap(a) + Custom.unwrap(b)); 5 | } 6 | 7 | function diff(Custom a, Custom b) pure returns (Custom) { 8 | return Custom.wrap(Custom.unwrap(a) - Custom.unwrap(b)); 9 | } 10 | 11 | using { plus as +, diff as - } for Custom global; 12 | 13 | function ops(Custom a, Custom b) pure returns (Custom, Custom) { 14 | return (a + b, a - b); 15 | } 16 | 17 | contract A { 18 | function a() virtual public { 19 | b(); 20 | } 21 | 22 | function b() internal {} 23 | } 24 | 25 | contract B is A { 26 | function a() virtual override public { 27 | b(); 28 | c(); 29 | } 30 | 31 | function c() internal {} 32 | } 33 | 34 | contract C { 35 | function d() internal {} 36 | function e() internal { 37 | Custom x = Custom.wrap(1); 38 | Custom y = Custom.wrap(2); 39 | 40 | x + y; 41 | x - y; 42 | 43 | ops(x, y); 44 | } 45 | } 46 | 47 | contract D is B, C { 48 | function a() virtual override public { 49 | b(); 50 | c(); 51 | d(); 52 | } 53 | } 54 | 55 | contract E is B {} 56 | -------------------------------------------------------------------------------- /test/samples/contract_decorated_ext_call.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.6.10; 2 | /// #invariant {:msg ""} x>0; 3 | contract Foo { 4 | int x = 1; 5 | function inc() public payable { 6 | x++; 7 | } 8 | 9 | function fail_int() internal { 10 | x = 0; 11 | // Should detect failure here 12 | this.inc.value(0)(); 13 | x = 0; 14 | // Should detect failure here 15 | this.inc.gas(10000)(); 16 | x = 0; 17 | // Should detect failure here 18 | this.inc.value(0).gas(10000)(); 19 | x = 0; 20 | // Should detect failure here 21 | this.inc{value: 0, gas: 10000}(); 22 | // At this point x>0 23 | } 24 | 25 | function fail() public { 26 | fail_int(); 27 | } 28 | 29 | function withdraw(uint _amount) public { 30 | (bool success, bytes memory retval) = msg.sender.call.value(_amount)(""); 31 | require(success); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test/samples/contract_decorated_ext_callv05.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.10; 2 | /// #invariant {:msg ""} x>0; 3 | contract Foo { 4 | int x = 1; 5 | function inc() public payable { 6 | x++; 7 | } 8 | 9 | function fail_int() internal { 10 | x = 0; 11 | // Should detect failure here 12 | this.inc.value(0)(); 13 | x = 0; 14 | // Should detect failure here 15 | this.inc.gas(10000)(); 16 | x = 0; 17 | // Should detect failure here 18 | this.inc.value(0).gas(10000)(); 19 | } 20 | 21 | function fail() public { 22 | fail_int(); 23 | } 24 | 25 | function withdraw(uint _amount) public { 26 | (bool success, bytes memory retval) = msg.sender.call.value(_amount)(""); 27 | require(success); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/samples/contract_multi_arg_debug.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.7; 2 | 3 | /// #invariant {:msg ""} b == a + c - 1; 4 | contract Foo { 5 | uint a=2; 6 | uint b=101; 7 | uint c=100; 8 | function inc5(uint x) external view returns (uint y) { 9 | return x+5; 10 | } 11 | } 12 | 13 | contract Base is Foo { 14 | function inc3(uint x) external returns (uint y) { 15 | a += x + 1; 16 | return x+1; 17 | } 18 | } 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/samples/contract_pos.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.6.10; 2 | /// #invariant {:msg ""} x>0; 3 | contract Foo { 4 | int x = 1; 5 | function inc() public { 6 | x++; 7 | } 8 | 9 | function add(int v) internal { 10 | x+=v; 11 | } 12 | 13 | function fail() public { 14 | add(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/samples/contract_pos_edge_cases.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.6.10; 2 | 3 | /// #invariant {:msg ""} x>0; 4 | contract PosConstructorFail { 5 | int x = 0; 6 | function inc() public { 7 | x++; 8 | } 9 | } 10 | 11 | // --------------------------------------------- 12 | 13 | /// #invariant {:msg ""} x>0; 14 | contract PosExtCallFail { 15 | int x = 1; 16 | function inc() public { 17 | x++; 18 | } 19 | 20 | function fail_int() internal { 21 | x = 0; 22 | // Should detect failure here 23 | this.inc(); 24 | // At this point x>0 25 | } 26 | 27 | function fail() public { 28 | fail_int(); 29 | } 30 | } 31 | 32 | // --------------------------------------------- 33 | 34 | interface IPosLibInterface { 35 | function boo() external; 36 | } 37 | 38 | library SillyMath { 39 | function add(int a, int b) public returns (int) { 40 | return a+b; 41 | } 42 | } 43 | 44 | /// #invariant {:msg ""} x>0; 45 | contract PosLibInterface is IPosLibInterface { 46 | using SillyMath for int; 47 | 48 | function boo() override external {} 49 | 50 | int x = 1; 51 | function inc() public { 52 | x++; 53 | } 54 | 55 | function add(int v) internal { 56 | x = x.add(v); 57 | } 58 | 59 | function fail() public { 60 | add(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /test/samples/crashingAnnotation.instrumented.sol: -------------------------------------------------------------------------------- 1 | /// This file is auto-generated by Scribble and shouldn't be edited directly. 2 | /// Use --disarm prior to make any changes. 3 | pragma solidity 0.7.5; 4 | 5 | contract Foo { 6 | struct vars0 { 7 | uint256 p; 8 | uint256 t; 9 | bool let_0; 10 | bool let_1; 11 | } 12 | 13 | function div(uint a, uint b) public returns (uint c) { 14 | vars0 memory _v; 15 | c = _original_Foo_div(a, b); 16 | _v.p = b; 17 | _v.t = a / _v.p; 18 | _v.let_0 = _v.t == c; 19 | _v.let_1 = _v.let_0; 20 | if (!(_v.let_1)) { 21 | emit __ScribbleUtilsLib__18.AssertionFailed("000527:0066:000 0: "); 22 | assert(false); 23 | } 24 | } 25 | 26 | function _original_Foo_div(uint a, uint b) internal pure returns (uint c) { 27 | return a / b; 28 | } 29 | } 30 | 31 | library __ScribbleUtilsLib__18 { 32 | event AssertionFailed(string message); 33 | 34 | event AssertionFailedData(int eventId, bytes encodingData); 35 | 36 | function assertionFailed(string memory arg_0) internal { 37 | emit AssertionFailed(arg_0); 38 | } 39 | 40 | function assertionFailedData(int arg_0, bytes memory arg_1) internal { 41 | emit AssertionFailedData(arg_0, arg_1); 42 | } 43 | 44 | function isInContract() internal returns (bool res) { 45 | assembly { 46 | res := sload(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c) 47 | } 48 | } 49 | 50 | function setInContract(bool v) internal { 51 | assembly { 52 | sstore(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c, v) 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /test/samples/crashingAnnotation.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.7.5; 2 | contract Foo { 3 | /// #if_succeeds let p := b in let t := a/p in t == c; 4 | function div(uint a, uint b) public pure returns (uint c) { 5 | return a/b; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/samples/custom_maps_0.4.26.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.4.26; 2 | 3 | contract Foo { 4 | mapping(address => uint256) private _valueMap; 5 | 6 | /// #if_succeeds forall(address a in _valueMap) _valueMap[a] > 0; 7 | function foo() public { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/samples/dbg_event_tests.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.4; 2 | contract Foo { 3 | /// #if_succeeds old(x) == 0; 4 | function changesArg1(uint x) public { 5 | x = 1; 6 | } 7 | 8 | /// #if_succeeds x == 0; 9 | function changesArg2(uint x) public { 10 | x = 1; 11 | // NOTE: For functions that modify the arguments, you still 12 | // always get the old value 13 | } 14 | 15 | uint[] x = [1,2]; 16 | /// #if_succeeds old(x[0]) == 0; 17 | function changesArr1() public { 18 | x[0] = 3; 19 | } 20 | 21 | /// #if_succeeds x[0] == 0; 22 | function changesArr2() public { 23 | x[0] = 4; 24 | } 25 | 26 | /// #if_succeeds RET == 1; 27 | function newRet() public returns (uint RET) { 28 | return 2; 29 | } 30 | 31 | /// #if_succeeds let x := x+1 in let x := x+1 in let x := x+1 in x + x == 8; 32 | function shadowing(uint x) public { 33 | } 34 | 35 | uint t = 1; 36 | /// #if_updated arr[t] == 3; 37 | uint[] arr = [0,0,0,0]; 38 | 39 | function updArr() public { 40 | arr[1] = 2; 41 | } 42 | 43 | /// #if_assigned[i] old(arr1[3]) == 3; 44 | uint[] arr1; 45 | 46 | constructor() { 47 | arr1 = [0,0,0,7]; 48 | } 49 | 50 | function updArrOld() public { 51 | arr1[3] = 8; 52 | } 53 | 54 | /// #if_assigned[str] m[str].length > 1; 55 | /// #if_assigned[str][ind] m[str][ind] > 0; 56 | mapping(string => uint[]) m; 57 | 58 | // Note that in the above annotations m will be skipped as its a map - not encodable :( 59 | function assignInd0() public { 60 | m["abc"] = [uint(1)]; 61 | } 62 | 63 | function assignInd1() public { 64 | m["abc"] = [1,2,3]; 65 | m["abc"][1] = 0; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /test/samples/filtering.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.6.10; 2 | 3 | /// #invariant {:msg "Low.P0"} x > 0; 4 | /// #invariant {:msg "Medium.P1"} x == 0; 5 | /// #invariant {:msg "Critical.P2"} x < 0; 6 | contract Foo { 7 | uint x; 8 | 9 | constructor (uint _x) public { 10 | x = _x; 11 | } 12 | 13 | /// #if_succeeds {:msg "Critical.P4"} b == a + 1; 14 | function foo(uint256 a) public returns (uint256 b) { 15 | return a + 1; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/samples/forall_and_if_updated.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.10; 2 | 3 | contract Foo { 4 | type CustomValueType is uint32; 5 | 6 | /// #if_updated forall(uint k in m) m[k][0] > 1; 7 | mapping(uint=>mapping(uint => uint)) m; 8 | 9 | /// #if_updated forall(CustomValueType t in _map) true; 10 | mapping(CustomValueType => uint) _map; 11 | 12 | function main() public { 13 | m[0][1] = 1; 14 | } 15 | 16 | function some(CustomValueType t, uint v) external { 17 | _map[t] = v; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/samples/forall_simple.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.4; 2 | 3 | /// #invariant forall (uint i in a) a[i] > 10; 4 | contract ForallSimple { 5 | uint[] a; 6 | function push(uint x) external { 7 | a.push(x); 8 | } 9 | 10 | /// #if_succeeds forall (uint i in a) let z1 := x in let z2 := a[i] in z2 > z1; 11 | function test1(uint[] memory a, uint x) public { 12 | } 13 | 14 | uint t = 0; 15 | /// #if_succeeds forall (uint i in a) a[i] > old(t); 16 | function test2(uint[] memory a, uint x) public { 17 | t = x; 18 | } 19 | 20 | uint t1 = 0; 21 | /// #if_succeeds old(forall (uint i in a) let x := a[i] in let y := t1 in x > y); 22 | function test3(uint[] memory a, uint x) public { 23 | t1 = x; 24 | } 25 | 26 | uint t2 = 0; 27 | /// #if_succeeds forall (uint i in a) forall (uint j in a[i]) a[i][j] > old(t2); 28 | function test4(uint[][] memory a, uint x) public { 29 | t2 = x; 30 | } 31 | 32 | /// #if_succeeds forall (uint i in 1...5) i >= 1 && i < 5; 33 | function test5() public { 34 | } 35 | 36 | /// #if_succeeds forall (uint i in 1...5) i > 1; 37 | function test6() public { 38 | } 39 | 40 | /// #if_succeeds forall (uint i in 1...5) i < 4; 41 | function test7() public { 42 | } 43 | 44 | /// #if_succeeds forall (uint i in 5...5) false; 45 | function test11() public { 46 | } 47 | 48 | /// #if_succeeds let MAX_INT := uint(2**255 - 1 + 2**255) in forall (uint i in MAX_INT...MAX_INT) false; 49 | function test12() public { 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /test/samples/hints.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.10; 2 | /// #require z > 1; 3 | /// #try msg.sender == address(0x0); 4 | contract Foo { 5 | uint z; 6 | 7 | 8 | /// #require x > 2; 9 | /// #try x < 10; 10 | function bar(uint x) public { 11 | 12 | /// #require x > 10; 13 | /// #try x == 9; 14 | uint z = x + 1; 15 | } 16 | 17 | function boo() public {} 18 | 19 | function baz() internal {} 20 | 21 | /// #try x == 1, y == 2; 22 | function test(uint x, uint y) public returns (uint) { 23 | uint a = 1; 24 | uint b = 2; 25 | /// #try a == 1, b == 2; 26 | return x + y + z + a + b; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/samples/if_assigned_complex.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.7; 2 | 3 | contract Base { 4 | //// #if_assigned x >= old(x); 5 | uint x; 6 | //// #if_updated arr.length > 0; 7 | //// #if_assigned[x] 0 <= x && x <= arr.length; 8 | uint[] arr; 9 | 10 | //// #if_updated arr2.length > 0; 11 | //// #if_assigned[x] 0 <= x && x <= arr2.length; 12 | //// #if_assigned[x][y] 0 <= y && y <= arr2[x].length; 13 | uint[][] arr2; 14 | 15 | struct S { 16 | uint[] arr; 17 | uint[][] arr2; 18 | } 19 | 20 | //// #if_assigned.arr[x] 0 <= x && x <= s.arr.length; 21 | //// #if_assigned.arr2[x][y] 0 <= y && y <= s.arr2[x].length; 22 | S s; 23 | 24 | constructor() { 25 | x = 1; 26 | } 27 | 28 | function main() public { 29 | arr.push(1); 30 | arr.push(2); 31 | arr[0] = 3; 32 | assert(arr[0] == 3 && arr[1] == 2); 33 | 34 | (arr[0], arr[1]) = (5, (6)); 35 | 36 | assert(arr[0] == 5 && arr[1] == 6); 37 | 38 | arr2.push(arr); 39 | arr2[0][1] = 7; 40 | 41 | assert(arr2[0][0] == 5 && arr2[0][1] == 7); 42 | 43 | arr2[0] = arr; 44 | 45 | assert(arr2[0][0] == 5 && arr2[0][1] == 6); 46 | s.arr.push(10); 47 | s.arr.push(11); 48 | assert(s.arr.length == 2 && s.arr[0] == 10 && s.arr[1] == 11); 49 | s.arr[0] = 12; 50 | s.arr[1] = 13; 51 | 52 | assert(s.arr.length == 2 && s.arr[0] == 12 && s.arr[1] == 13); 53 | 54 | s.arr2.push(s.arr); 55 | 56 | assert(s.arr2.length == 1 && s.arr2[0][0] == 12 && s.arr2[0][1] == 13); 57 | s.arr2[0] = s.arr; 58 | s.arr2[0][1] = 14; 59 | assert(s.arr2[0][1] == 14); 60 | } 61 | } 62 | 63 | 64 | contract Child is Base { 65 | function moo() public { 66 | arr[0] = 10; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /test/samples/if_assigned_inline_initializers.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.7; 2 | 3 | contract Base { 4 | //// #if_assigned x >= old(x); 5 | uint x; 6 | //// #if_updated arr.length > 0; 7 | //// #if_assigned[x] 0 <= x && x <= arr.length; 8 | uint[] arr = [1]; 9 | 10 | //// #if_updated arr2.length > 0; 11 | //// #if_assigned[x] 0 <= x && x <= arr2.length; 12 | //// #if_assigned[x][y] 0 <= y && y <= arr2[x].length; 13 | uint[][] arr2 = [[1,2], [3,4]]; 14 | 15 | struct S { 16 | uint[] arr; 17 | uint[][] arr2; 18 | } 19 | 20 | //// #if_assigned s.arr.length > 0; 21 | //// #if_assigned.arr[x] 0 <= x && x <= s.arr.length; 22 | //// #if_assigned.arr2[x][y] 0 <= y && y <= s.arr2[x].length; 23 | S s = S({arr:arr, arr2: arr2}); 24 | 25 | constructor() { 26 | x = 1; 27 | } 28 | } 29 | 30 | contract Child is Base { 31 | constructor() public { 32 | x = 4; 33 | arr = [4]; 34 | arr2 = [[1], [2]]; 35 | s.arr = arr; 36 | s.arr2 = arr2; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /test/samples/if_assigned_primitive.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.7; 2 | 3 | contract Base { 4 | //// #if_assigned x >=1; 5 | uint x = 1; 6 | //// #if_assigned y >= old(y); 7 | uint y; 8 | 9 | uint z; 10 | 11 | //// #if_assigned uint160(a) >= 1; 12 | address a = address(0x1); 13 | 14 | uint[] arr; 15 | constructor() { 16 | y = 2; 17 | x = 2; 18 | a = address(0x2); 19 | } 20 | 21 | function id(uint z) internal returns (uint) { 22 | return z; 23 | } 24 | 25 | function main() public { 26 | x++; 27 | assert(x == 3); 28 | for (x = 5; x < 10; x++) y++; 29 | assert(x == 10 && y == 7); 30 | 31 | x = x = 5; 32 | assert(x == 6); 33 | 34 | x = id(x = 6); 35 | assert(x == 7); 36 | 37 | delete x; 38 | assert(x == 0); 39 | 40 | y = y + 1; 41 | assert(y == 8); 42 | 43 | x = x++; 44 | assert(x == 0); 45 | 46 | x = ++x; 47 | assert(x == 1); 48 | 49 | arr.push(1); 50 | 51 | arr.push(2); 52 | } 53 | } 54 | 55 | 56 | contract Child is Base { 57 | function moo() public { 58 | x = 1; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /test/samples/if_succeeds_on_contract.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.7.0; 2 | 3 | 4 | /// #if_succeeds {:msg ""} b == a + old(1); 5 | /// #if_succeeds {:msg ""} b == a&1; 6 | contract Foo { 7 | uint a; 8 | uint b; 9 | /// #if_succeeds {:msg ""} b == a^1; 10 | function inc(uint x) public returns (uint y) { 11 | return x+1; 12 | } 13 | 14 | function inc2(uint x) external view returns (uint y) { 15 | return x+1; 16 | } 17 | 18 | function inc3(uint x) private view returns (uint y) { 19 | return x+1; 20 | } 21 | 22 | function inc4(uint x) internal view returns (uint y) { 23 | return x+1; 24 | } 25 | 26 | function inc5(uint x) public pure returns (uint y) { 27 | return x+2; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/samples/if_succeeds_on_contract_inheritance.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.7.0; 2 | 3 | /// #if_succeeds {:msg ""} b == a + 1; 4 | contract Foo { 5 | uint a; 6 | uint b; 7 | 8 | function inc(uint x) public returns (uint y) { 9 | return x+1; 10 | } 11 | function inc2(uint x) virtual public returns(uint y){ 12 | 13 | } 14 | } 15 | 16 | contract Bar is Foo { 17 | function inc2(uint x) public override returns (uint y) { 18 | return x+3; 19 | } 20 | function inc3(uint x) public pure returns (uint y) { 21 | return x+5; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /test/samples/if_succeeds_on_statement.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.11; 2 | contract IfSucceedsOnStatement { 3 | function foo(uint amount) public { 4 | uint[] memory a; 5 | for(uint i = 0; i < a.length; i++) { 6 | /// #if_succeeds old(a[i]) + amount == a[i]; 7 | a[i] += amount; 8 | } 9 | } 10 | 11 | function boo(uint amount) public { 12 | uint[] memory a; 13 | for(uint i = 0; i < a.length; i++) 14 | /// #if_succeeds old(a[i]) + amount == a[i]; 15 | { 16 | 17 | a[i] += amount; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/samples/if_updated_aliasing.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.7; 2 | 3 | contract IfUpdatedAliasing { 4 | //// #if_updated true; 5 | uint[] a1; 6 | uint[] a2; 7 | uint[] a3; 8 | uint[] a4; 9 | 10 | //// #if_updated true; 11 | uint[][] aa1; 12 | uint[][] aa2; 13 | 14 | 15 | function main() public { 16 | a1.push(1); 17 | // Aliasing is ok, as long as the aliased variable doesn't have annotations 18 | uint[] storage p = a2; 19 | p.push(2); 20 | 21 | (a1[0], p[0]) = (p[0], a1[0]); 22 | assert(a1[0] == 2 && a2[0] == 1); 23 | 24 | aa1.push(a1); 25 | uint[][] storage pp = aa2; 26 | pp.push(a2); 27 | 28 | assert(aa1[0][0] == 2 && aa2[0][0] == 1); 29 | (aa1[0], pp[0]) = (pp[0], aa1[0]); 30 | 31 | assert(aa1[0][0] == 2 && aa2[0][0] == 2); 32 | 33 | uint i; 34 | (p, i) = 1 > 2 ? (a2, 1) : 2>3 ? (a3, 2) : (a4, 3); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /test/samples/if_updated_fun_return_ptr.instrumented.sol: -------------------------------------------------------------------------------- 1 | /// This file is auto-generated by Scribble and shouldn't be edited directly. 2 | /// Use --disarm prior to make any changes. 3 | pragma solidity 0.4.26; 4 | 5 | contract Foo { 6 | uint[] internal arr; 7 | int8[] internal arr1; 8 | 9 | function getPtr() internal returns (int8[] storage) { 10 | return arr1; 11 | } 12 | 13 | function main() public { 14 | getPtr().push(0); 15 | Foo_arr_uint256_push(1); 16 | } 17 | 18 | function Foo_arr_uint256_push(uint256 ARG0) internal { 19 | arr.push(ARG0); 20 | if (!(arr.length > 0)) { 21 | __ScribbleUtilsLib__33.assertionFailed("000523:0061:000 0: "); 22 | assert(false); 23 | } 24 | } 25 | } 26 | 27 | library __ScribbleUtilsLib__33 { 28 | event AssertionFailed(string message); 29 | 30 | event AssertionFailedData(int eventId, bytes encodingData); 31 | 32 | function assertionFailed(string memory arg_0) internal { 33 | emit AssertionFailed(arg_0); 34 | } 35 | 36 | function assertionFailedData(int arg_0, bytes memory arg_1) internal { 37 | emit AssertionFailedData(arg_0, arg_1); 38 | } 39 | 40 | function isInContract() internal returns (bool res) { 41 | assembly { 42 | res := sload(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c) 43 | } 44 | } 45 | 46 | function setInContract(bool v) internal { 47 | assembly { 48 | sstore(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c, v) 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /test/samples/if_updated_fun_return_ptr.sol: -------------------------------------------------------------------------------- 1 | contract Foo { 2 | /// #if_updated arr.length > 0; 3 | uint[] arr; 4 | 5 | int8[] arr1; 6 | function getPtr() internal returns (int8[] storage) { 7 | return arr1; 8 | } 9 | 10 | function main() { 11 | getPtr().push(0); 12 | 13 | arr.push(1); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/samples/if_updated_inline_initializers.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.7; 2 | 3 | contract Base { 4 | //// #if_updated x >= old(x); 5 | uint x; 6 | //// #if_updated arr.length > 0; 7 | uint[] arr = [1]; 8 | 9 | //// #if_updated arr2.length > 0; 10 | uint[][] arr2 = [[1,2], [3,4]]; 11 | 12 | struct S { 13 | uint[] arr; 14 | uint[][] arr2; 15 | } 16 | 17 | //// #if_updated s.arr.length > 0; 18 | S s = S({arr:arr, arr2: arr2}); 19 | 20 | constructor() { 21 | x = 1; 22 | } 23 | } 24 | 25 | contract Child is Base { 26 | constructor() public { 27 | x = 4; 28 | arr = [4]; 29 | arr2 = [[1], [2]]; 30 | s.arr = arr; 31 | s.arr2 = arr2; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test/samples/if_updated_primitive.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.7; 2 | 3 | contract Base { 4 | //// #if_updated x >=1; 5 | uint x = 1; 6 | //// #if_updated y >= old(y); 7 | uint y; 8 | 9 | uint z; 10 | 11 | //// #if_updated t == 0; 12 | uint t; 13 | 14 | //// #if_updated uint160(a) >= 1; 15 | address a = address(0x1); 16 | 17 | uint[] arr; 18 | constructor() { 19 | x = 2; 20 | y = 2; 21 | a = address(0x2); 22 | } 23 | 24 | function id(uint z) internal returns (uint) { 25 | return z; 26 | } 27 | 28 | function main() public { 29 | x++; 30 | 31 | for (x = 5; x < 10; x++) y++; 32 | 33 | x = x = 5; 34 | 35 | x = id(x = 6); 36 | 37 | delete t; 38 | 39 | y = y + 1; 40 | 41 | x = x++; 42 | assert(x == 6); 43 | 44 | x = ++x; 45 | assert(x == 7); 46 | 47 | arr.push(1); 48 | 49 | arr.push(2); 50 | } 51 | } 52 | 53 | 54 | contract Child is Base { 55 | function moo() public { 56 | x = 1; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /test/samples/if_updated_swap.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | contract PointerSwap { 4 | //// #if_updated true; 5 | uint[] a = [1,2,3]; 6 | uint[] b = [4,5,6]; 7 | 8 | function main() public { 9 | (a, b) = (b, a); 10 | 11 | assert(a[0] == 4 && b[0] == 1); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/samples/if_updated_tuples.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.7; 2 | 3 | contract IfUpdatedPrimitive { 4 | //// #if_updated x >=1; 5 | uint x = 1; 6 | uint y = 2; 7 | 8 | //// #if_updated uint160(a) >= 1; 9 | address a = address(0x1); 10 | 11 | constructor() { 12 | x = 2; 13 | a = address(0x2); 14 | } 15 | 16 | function getTwo() internal returns (uint, address) { 17 | return (4, address(0x4)); 18 | } 19 | 20 | function id(uint z) internal returns (uint) { 21 | return z; 22 | } 23 | 24 | function main() public { 25 | (x, a) = (x+1, address(uint160(a)+1)); 26 | assert(x == 3 && a == address(0x3)); 27 | (x, y) = (y, x); 28 | assert(x == 2 && y == 3); 29 | 30 | (x, a) = getTwo(); 31 | assert(x == 4); 32 | 33 | x = 1; 34 | 35 | // Should be disallowed 36 | // (y, (x, y)) = (1, getTwo()); 37 | 38 | (y, (x, a)) = (1, getTwo()); 39 | assert(y == 1 && x == 4); 40 | 41 | (x,y) = y == 1 ? (3, 4) : (5,6); 42 | assert(x == 3 && y == 4); 43 | 44 | (x,y) = (x == 0) ? (0, 0) : (x == 3) ? (1, 1) : (0, 0); 45 | 46 | assert(x == 1 && y == 1); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /test/samples/if_updated_unsafe.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.7; 2 | 3 | /// #define id(uint x) uint = x + 1 - 1; 4 | contract TestUnchecked { 5 | //// #if_assigned {:msg "A1"} id(x) > 0; 6 | //// #if_updated {:msg "U1"} x > 0; 7 | uint8 x = 100; 8 | 9 | /// #if_succeeds {:msg "S1"} x == 1; 10 | function foo() public { 11 | x = 254; 12 | 13 | x += 1; 14 | 15 | unchecked { 16 | x += 2; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/samples/immutables.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.20; 2 | /// #if_succeeds x == 5; 3 | contract Example01 { 4 | uint private immutable x; 5 | 6 | constructor() { 7 | x = 5; 8 | } 9 | } 10 | 11 | contract Example02 { 12 | uint private immutable x; 13 | 14 | /// #if_succeeds x == 5; 15 | constructor() { 16 | x = 5; 17 | } 18 | } 19 | 20 | /// #require y == 1; 21 | contract Example03 { 22 | uint private immutable x; 23 | uint y = 1; 24 | 25 | constructor() { 26 | x = 5; 27 | } 28 | } 29 | 30 | contract Example04 { 31 | uint private immutable x; 32 | uint y = 1; 33 | 34 | /// #require y == 1; 35 | constructor() { 36 | x = 5; 37 | } 38 | } 39 | 40 | 41 | -------------------------------------------------------------------------------- /test/samples/increment.instrumented.sol: -------------------------------------------------------------------------------- 1 | /// This file is auto-generated by Scribble and shouldn't be edited directly. 2 | /// Use --disarm prior to make any changes. 3 | pragma solidity 0.6.10; 4 | 5 | contract Foo { 6 | function foo(uint256 x) public returns (uint256 y) { 7 | y = _original_Foo_foo(x); 8 | if (!(y == (x + 1))) { 9 | emit __ScribbleUtilsLib__16.AssertionFailed("000296:0068:000 0: P0"); 10 | assert(false); 11 | } 12 | } 13 | 14 | function _original_Foo_foo(uint256 x) internal returns (uint256 y) { 15 | return x + 1; 16 | } 17 | } 18 | 19 | library __ScribbleUtilsLib__16 { 20 | event AssertionFailed(string message); 21 | 22 | event AssertionFailedData(int eventId, bytes encodingData); 23 | 24 | function assertionFailed(string memory arg_0) internal { 25 | emit AssertionFailed(arg_0); 26 | } 27 | 28 | function assertionFailedData(int arg_0, bytes memory arg_1) internal { 29 | emit AssertionFailedData(arg_0, arg_1); 30 | } 31 | 32 | function isInContract() internal returns (bool res) { 33 | assembly { 34 | res := sload(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c) 35 | } 36 | } 37 | 38 | function setInContract(bool v) internal { 39 | assembly { 40 | sstore(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c, v) 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /test/samples/increment.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.6.10; 2 | contract Foo { 3 | /// #if_succeeds {:msg "P0"} y == x+1; 4 | function foo(uint256 x) public returns (uint256 y) { 5 | return x + 1; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/samples/increment_inherited.instrumented.sol: -------------------------------------------------------------------------------- 1 | /// This file is auto-generated by Scribble and shouldn't be edited directly. 2 | /// Use --disarm prior to make any changes. 3 | pragma solidity 0.5.17; 4 | 5 | contract Base { 6 | /// #if_succeeds {:msg "P0"} y == x+1; 7 | function foo(uint256 x) public returns (uint256 y); 8 | } 9 | 10 | library __ScribbleUtilsLib__25 { 11 | event AssertionFailed(string message); 12 | 13 | event AssertionFailedData(int eventId, bytes encodingData); 14 | 15 | function assertionFailed(string memory arg_0) internal { 16 | emit AssertionFailed(arg_0); 17 | } 18 | 19 | function assertionFailedData(int arg_0, bytes memory arg_1) internal { 20 | emit AssertionFailedData(arg_0, arg_1); 21 | } 22 | 23 | function isInContract() internal returns (bool res) { 24 | assembly { 25 | res := sload(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c) 26 | } 27 | } 28 | 29 | function setInContract(bool v) internal { 30 | assembly { 31 | sstore(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c, v) 32 | } 33 | } 34 | } 35 | 36 | contract Foo is Base { 37 | function foo(uint256 x) public returns (uint256 y) { 38 | y = _original_Foo_foo(x); 39 | if (!(y == (x + 1))) { 40 | __ScribbleUtilsLib__25.assertionFailed("001160:0063:000 0: P0"); 41 | assert(false); 42 | } 43 | } 44 | 45 | function _original_Foo_foo(uint256 x) internal returns (uint256 y) { 46 | return x + 1; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /test/samples/increment_inherited.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | contract Base { 4 | /// #if_succeeds {:msg "P0"} y == x+1; 5 | function foo(uint256 x) public returns (uint256 y); 6 | } 7 | 8 | contract Foo is Base { 9 | function foo(uint256 x) public returns (uint256 y) { 10 | return x + 1; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/samples/increment_inherited2.instrumented.sol: -------------------------------------------------------------------------------- 1 | /// This file is auto-generated by Scribble and shouldn't be edited directly. 2 | /// Use --disarm prior to make any changes. 3 | pragma solidity 0.5.17; 4 | 5 | contract Base { 6 | /// #if_succeeds {:msg "P0"} y > 1; 7 | function foo(uint256 x) public returns (uint256 y); 8 | } 9 | 10 | library __ScribbleUtilsLib__25 { 11 | event AssertionFailed(string message); 12 | 13 | event AssertionFailedData(int eventId, bytes encodingData); 14 | 15 | function assertionFailed(string memory arg_0) internal { 16 | emit AssertionFailed(arg_0); 17 | } 18 | 19 | function assertionFailedData(int arg_0, bytes memory arg_1) internal { 20 | emit AssertionFailedData(arg_0, arg_1); 21 | } 22 | 23 | function isInContract() internal returns (bool res) { 24 | assembly { 25 | res := sload(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c) 26 | } 27 | } 28 | 29 | function setInContract(bool v) internal { 30 | assembly { 31 | sstore(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c, v) 32 | } 33 | } 34 | } 35 | 36 | contract Foo is Base { 37 | function foo(uint256 x) public returns (uint256 y) { 38 | y = _original_Foo_foo(x); 39 | if (!(y > 1)) { 40 | __ScribbleUtilsLib__25.assertionFailed("001150:0063:000 0: P0"); 41 | assert(false); 42 | } 43 | if (!(y == (x + 1))) { 44 | __ScribbleUtilsLib__25.assertionFailed("001295:0063:000 1: P0"); 45 | assert(false); 46 | } 47 | } 48 | 49 | function _original_Foo_foo(uint256 x) internal returns (uint256 y) { 50 | return x + 1; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /test/samples/increment_inherited2.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | contract Base { 4 | /// #if_succeeds {:msg "P0"} y > 1; 5 | function foo(uint256 x) public returns (uint256 y); 6 | } 7 | 8 | contract Foo is Base { 9 | /// #if_succeeds {:msg "P0"} y == x+1; 10 | function foo(uint256 x) public returns (uint256 y) { 11 | return x + 1; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/samples/increment_inherited3.instrumented.sol: -------------------------------------------------------------------------------- 1 | /// This file is auto-generated by Scribble and shouldn't be edited directly. 2 | /// Use --disarm prior to make any changes. 3 | pragma solidity 0.5.17; 4 | 5 | contract Base { 6 | function foo(uint256 x) public returns (uint256 y) { 7 | y = _original_Base_foo(x); 8 | if (!(y > x)) { 9 | __ScribbleUtilsLib__30.assertionFailed("000291:0063:000 0: P0"); 10 | assert(false); 11 | } 12 | } 13 | 14 | function _original_Base_foo(uint256 x) internal returns (uint256 y) { 15 | return x + 2; 16 | } 17 | } 18 | 19 | library __ScribbleUtilsLib__30 { 20 | event AssertionFailed(string message); 21 | 22 | event AssertionFailedData(int eventId, bytes encodingData); 23 | 24 | function assertionFailed(string memory arg_0) internal { 25 | emit AssertionFailed(arg_0); 26 | } 27 | 28 | function assertionFailedData(int arg_0, bytes memory arg_1) internal { 29 | emit AssertionFailedData(arg_0, arg_1); 30 | } 31 | 32 | function isInContract() internal returns (bool res) { 33 | assembly { 34 | res := sload(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c) 35 | } 36 | } 37 | 38 | function setInContract(bool v) internal { 39 | assembly { 40 | sstore(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c, v) 41 | } 42 | } 43 | } 44 | 45 | contract Foo is Base { 46 | function foo(uint256 x) public returns (uint256 y) { 47 | y = _original_Foo_foo(x); 48 | if (!(y > x)) { 49 | __ScribbleUtilsLib__30.assertionFailed("001393:0063:000 0: P0"); 50 | assert(false); 51 | } 52 | if (!(y == (x + 1))) { 53 | __ScribbleUtilsLib__30.assertionFailed("001538:0063:000 1: P0"); 54 | assert(false); 55 | } 56 | } 57 | 58 | function _original_Foo_foo(uint256 x) internal returns (uint256 y) { 59 | return x + 1; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /test/samples/increment_inherited3.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | contract Base { 4 | /// #if_succeeds {:msg "P0"} y > x; 5 | function foo(uint256 x) public returns (uint256 y) { 6 | return x+2; 7 | } 8 | } 9 | 10 | contract Foo is Base { 11 | /// #if_succeeds {:msg "P0"} y == x+1; 12 | function foo(uint256 x) public returns (uint256 y) { 13 | return x + 1; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/samples/increment_inherited3_v06.instrumented.sol: -------------------------------------------------------------------------------- 1 | /// This file is auto-generated by Scribble and shouldn't be edited directly. 2 | /// Use --disarm prior to make any changes. 3 | pragma solidity 0.6.10; 4 | 5 | contract Base { 6 | function foo(uint256 x) virtual public returns (uint256 y) { 7 | y = _original_Base_foo(x); 8 | if (!(y > x)) { 9 | emit __ScribbleUtilsLib__33.AssertionFailed("000299:0068:000 0: P0"); 10 | assert(false); 11 | } 12 | } 13 | 14 | function _original_Base_foo(uint256 x) internal returns (uint256 y) { 15 | return x + 2; 16 | } 17 | } 18 | 19 | library __ScribbleUtilsLib__33 { 20 | event AssertionFailed(string message); 21 | 22 | event AssertionFailedData(int eventId, bytes encodingData); 23 | 24 | function assertionFailed(string memory arg_0) internal { 25 | emit AssertionFailed(arg_0); 26 | } 27 | 28 | function assertionFailedData(int arg_0, bytes memory arg_1) internal { 29 | emit AssertionFailedData(arg_0, arg_1); 30 | } 31 | 32 | function isInContract() internal returns (bool res) { 33 | assembly { 34 | res := sload(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c) 35 | } 36 | } 37 | 38 | function setInContract(bool v) internal { 39 | assembly { 40 | sstore(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c, v) 41 | } 42 | } 43 | } 44 | 45 | contract Foo is Base { 46 | function foo(uint256 x) override public returns (uint256 y) { 47 | y = _original_Foo_foo(x); 48 | if (!(y > x)) { 49 | emit __ScribbleUtilsLib__33.AssertionFailed("001415:0068:000 0: P0"); 50 | assert(false); 51 | } 52 | if (!(y == (x + 1))) { 53 | emit __ScribbleUtilsLib__33.AssertionFailed("001565:0068:000 1: P0"); 54 | assert(false); 55 | } 56 | } 57 | 58 | function _original_Foo_foo(uint256 x) internal returns (uint256 y) { 59 | return x + 1; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /test/samples/increment_inherited3_v06.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.6.10; 2 | 3 | contract Base { 4 | /// #if_succeeds {:msg "P0"} y > x; 5 | function foo(uint256 x) public virtual returns (uint256 y) { 6 | return x+2; 7 | } 8 | } 9 | 10 | contract Foo is Base { 11 | /// #if_succeeds {:msg "P0"} y == x+1; 12 | function foo(uint256 x) public override returns (uint256 y) { 13 | return x + 1; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/samples/increment_inherited4.instrumented.sol: -------------------------------------------------------------------------------- 1 | /// This file is auto-generated by Scribble and shouldn't be edited directly. 2 | /// Use --disarm prior to make any changes. 3 | pragma solidity 0.5.17; 4 | 5 | contract Base { 6 | function foo(uint256 x) public returns (uint256 y) { 7 | return x + 2; 8 | } 9 | } 10 | 11 | contract Test { 12 | function main() public { 13 | Foo f = new Foo(); 14 | Base b = Base(f); 15 | b.foo(0); 16 | } 17 | } 18 | 19 | library __ScribbleUtilsLib__53 { 20 | event AssertionFailed(string message); 21 | 22 | event AssertionFailedData(int eventId, bytes encodingData); 23 | 24 | function assertionFailed(string memory arg_0) internal { 25 | emit AssertionFailed(arg_0); 26 | } 27 | 28 | function assertionFailedData(int arg_0, bytes memory arg_1) internal { 29 | emit AssertionFailedData(arg_0, arg_1); 30 | } 31 | 32 | function isInContract() internal returns (bool res) { 33 | assembly { 34 | res := sload(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c) 35 | } 36 | } 37 | 38 | function setInContract(bool v) internal { 39 | assembly { 40 | sstore(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c, v) 41 | } 42 | } 43 | } 44 | 45 | contract Foo is Base { 46 | function foo(uint256 x) public returns (uint256 y) { 47 | y = _original_Foo_foo(x); 48 | if (!(x > 10)) { 49 | __ScribbleUtilsLib__53.assertionFailed("001265:0063:000 0: P0"); 50 | assert(false); 51 | } 52 | } 53 | 54 | function _original_Foo_foo(uint256 x) internal returns (uint256 y) { 55 | return x + 1; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /test/samples/increment_inherited4.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | contract Base { 4 | function foo(uint256 x) public returns (uint256 y) { 5 | return x+2; 6 | } 7 | } 8 | 9 | contract Foo is Base { 10 | /// #if_succeeds {:msg "P0"} x>10; 11 | function foo(uint256 x) public returns (uint256 y) { 12 | return x + 1; 13 | } 14 | } 15 | 16 | contract Test { 17 | function main() public { 18 | Foo f = new Foo(); 19 | Base b = Base(f); 20 | 21 | b.foo(0); // This should still fail. 22 | } 23 | } -------------------------------------------------------------------------------- /test/samples/increment_inherited_collision.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.7.5; 2 | 3 | abstract contract __scribble_ReentrancyUtils { 4 | uint __scribble_out_of_contract; 5 | enum vars0 { 6 | A 7 | } 8 | 9 | enum vars1 { 10 | B 11 | } 12 | 13 | enum vars2 { 14 | C 15 | } 16 | 17 | function __scribble_check_state_invariants(uint x) public returns (uint) { 18 | return x; 19 | } 20 | 21 | function __scribble_check_state_invariants() public { 22 | assert(false); 23 | } 24 | 25 | function __scribble___scribble_ReentrancyUtils_check_state_invariants_internal() internal { 26 | assert(false); 27 | } 28 | 29 | /// #if_succeeds {:msg "P0"} let foo := y in 30 | /// let __mstore_scratch__ := foo in 31 | /// let __scribble_check_invs_at_end := __mstore_scratch__ in 32 | /// __scribble_check_invs_at_end == _v+1; 33 | function foo(uint256 _v) virtual public returns (uint256 y); 34 | 35 | function _original_Foo_foo(uint256 _v) private returns (uint256 y) { 36 | return _v; 37 | } 38 | } 39 | 40 | /// #invariant {:msg ""} t >= 1; 41 | contract Foo is __scribble_ReentrancyUtils { 42 | uint t = 1; 43 | function foo(uint256 _v) override public returns (uint256 y) { 44 | t++; 45 | return _v + 1; 46 | } 47 | 48 | function __scribble_Foo_check_state_invariants_internal() internal { 49 | assert(false); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /test/samples/increment_inheritedv6.instrumented.sol: -------------------------------------------------------------------------------- 1 | /// This file is auto-generated by Scribble and shouldn't be edited directly. 2 | /// Use --disarm prior to make any changes. 3 | pragma solidity 0.6.10; 4 | 5 | abstract contract Base { 6 | /// #if_succeeds {:msg "P0"} y == x+1; 7 | function foo(uint256 x) virtual public returns (uint256 y); 8 | } 9 | 10 | library __ScribbleUtilsLib__27 { 11 | event AssertionFailed(string message); 12 | 13 | event AssertionFailedData(int eventId, bytes encodingData); 14 | 15 | function assertionFailed(string memory arg_0) internal { 16 | emit AssertionFailed(arg_0); 17 | } 18 | 19 | function assertionFailedData(int arg_0, bytes memory arg_1) internal { 20 | emit AssertionFailedData(arg_0, arg_1); 21 | } 22 | 23 | function isInContract() internal returns (bool res) { 24 | assembly { 25 | res := sload(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c) 26 | } 27 | } 28 | 29 | function setInContract(bool v) internal { 30 | assembly { 31 | sstore(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c, v) 32 | } 33 | } 34 | } 35 | 36 | contract Foo is Base { 37 | function foo(uint256 x) override public returns (uint256 y) { 38 | y = _original_Foo_foo(x); 39 | if (!(y == (x + 1))) { 40 | emit __ScribbleUtilsLib__27.AssertionFailed("001186:0068:000 0: P0"); 41 | assert(false); 42 | } 43 | } 44 | 45 | function _original_Foo_foo(uint256 x) internal returns (uint256 y) { 46 | return x + 1; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /test/samples/increment_inheritedv6.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.6.10; 2 | 3 | abstract contract Base { 4 | /// #if_succeeds {:msg "P0"} y == x+1; 5 | function foo(uint256 x) public virtual returns (uint256 y); 6 | } 7 | 8 | contract Foo is Base { 9 | function foo(uint256 x) public override returns (uint256 y) { 10 | return x + 1; 11 | } 12 | } -------------------------------------------------------------------------------- /test/samples/increment_multiline.instrumented.sol: -------------------------------------------------------------------------------- 1 | /// This file is auto-generated by Scribble and shouldn't be edited directly. 2 | /// Use --disarm prior to make any changes. 3 | pragma solidity 0.6.10; 4 | 5 | contract Foo { 6 | function foo(uint256 x) public returns (uint256 y) { 7 | y = _original_Foo_foo(x); 8 | if (!(y == (x + 1))) { 9 | emit __ScribbleUtilsLib__29.AssertionFailed("000296:0068:000 0: P0"); 10 | assert(false); 11 | } 12 | } 13 | 14 | function _original_Foo_foo(uint256 x) internal returns (uint256 y) { 15 | return x + 1; 16 | } 17 | 18 | function boo(uint256 x) public returns (uint256 y) { 19 | y = _original_Foo_boo(x); 20 | if (!(y == (x + 1))) { 21 | emit __ScribbleUtilsLib__29.AssertionFailed("000646:0068:000 1: P0"); 22 | assert(false); 23 | } 24 | } 25 | 26 | function _original_Foo_boo(uint256 x) internal returns (uint256 y) { 27 | return x + 1; 28 | } 29 | } 30 | 31 | library __ScribbleUtilsLib__29 { 32 | event AssertionFailed(string message); 33 | 34 | event AssertionFailedData(int eventId, bytes encodingData); 35 | 36 | function assertionFailed(string memory arg_0) internal { 37 | emit AssertionFailed(arg_0); 38 | } 39 | 40 | function assertionFailedData(int arg_0, bytes memory arg_1) internal { 41 | emit AssertionFailedData(arg_0, arg_1); 42 | } 43 | 44 | function isInContract() internal returns (bool res) { 45 | assembly { 46 | res := sload(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c) 47 | } 48 | } 49 | 50 | function setInContract(bool v) internal { 51 | assembly { 52 | sstore(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c, v) 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /test/samples/increment_multiline.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.6.10; 2 | contract Foo { 3 | /// #if_succeeds {:msg "P0"} 4 | /// y == x+1; 5 | function foo(uint256 x) public returns (uint256 y) { 6 | return x + 1; 7 | } 8 | 9 | /** 10 | * #if_succeeds 11 | * 12 | * {:msg "P0"} 13 | * 14 | * y == x+1; 15 | */ 16 | function boo(uint256 x) public returns (uint256 y) { 17 | return x + 1; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/samples/inheritance_specifiers.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.7; 2 | 3 | contract A { 4 | uint public a; 5 | constructor(uint _a) { require(_a >= 0); a = _a; } 6 | } 7 | 8 | /// #invariant a > 0; 9 | contract B is A { 10 | constructor() A(1) {} 11 | } 12 | 13 | -------------------------------------------------------------------------------- /test/samples/invalid/ambiguous_binding1.invalid.sol: -------------------------------------------------------------------------------- 1 | /// #invariant let a := 1 in a > 0; 2 | contract Foo { 3 | } 4 | 5 | -------------------------------------------------------------------------------- /test/samples/invalid/ambiguous_binding2.invalid.sol: -------------------------------------------------------------------------------- 1 | /// #invariant (let a := true in 0) == 0; 2 | contract Foo { 3 | } 4 | 5 | -------------------------------------------------------------------------------- /test/samples/invalid/annotation_multiline2_syntax_error.invalid.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.6.10; 2 | contract Test { 3 | /** 4 | * Leading string 5 | * 6 | * #if_succeeds {:msg "P0"} y 7 | * \o/ x; 8 | * 9 | * Trailing string 10 | */ 11 | function foo(uint256 x) public returns (uint256 y) { 12 | return x + 1; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/samples/invalid/annotation_multiline_syntax_error.invalid.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.6.10; 2 | contract Test { 3 | /// Leading string 4 | /// 5 | /// #if_succeeds {:msg "P0"} y 6 | /// \o/ x; 7 | /// 8 | /// Trailing string 9 | function foo(uint256 x) public returns (uint256 y) { 10 | return x + 1; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/samples/invalid/annotation_sem_error.invalid.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.6.10; 2 | contract Test { 3 | /// Leading string 4 | /// 5 | /// #if_succeeds {:msg "P0"} x+y; 6 | /// 7 | /// Trailing string 8 | function foo(uint256 x) public returns (uint256 y) { 9 | return x + 1; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/samples/invalid/annotation_syntax_error.invalid.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.6.10; 2 | contract Test { 3 | /// Leading string 4 | /// 5 | /// #if_succeeds {:msg "P0"} y \o/ x; 6 | /// 7 | /// Trailing string 8 | function foo(uint256 x) public returns (uint256 y) { 9 | return x + 1; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/samples/invalid/annotation_type_error.invalid.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.6.10; 2 | contract Test { 3 | /// Leading string 4 | /// 5 | /// #if_succeeds {:msg "P0"} !x; 6 | /// 7 | /// Trailing string 8 | function foo(uint256 x) public returns (uint256 y) { 9 | return x + 1; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/samples/invalid/assert_try_catch.invalid.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.7; 2 | 3 | contract Foo { 4 | function main(uint n) public { 5 | try this.main(0) { 6 | 7 | } /** #assert true; */ catch Error(string memory errmsg) { 8 | 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/samples/invalid/consts_diff_contracts.invalid.sol: -------------------------------------------------------------------------------- 1 | /// #const uint256 H := 60 * 60; 2 | /// #const uint256 D := H * 24; 3 | contract A { 4 | /// #if_succeeds D == H * 24; 5 | function testHD() public {} 6 | } 7 | 8 | /// #const uint256 W := D * 7; 9 | contract B { 10 | /// #if_succeeds W == D * 7 && D == H * 24 && H == 60 * 60; 11 | function testWHD() public {} 12 | } 13 | 14 | contract C is B { 15 | /// #if_succeeds old(W) == D * 7; 16 | constructor() {} 17 | } 18 | -------------------------------------------------------------------------------- /test/samples/invalid/consts_non_const.invalid.sol: -------------------------------------------------------------------------------- 1 | /// #const uint256 H := msg.value; 2 | contract A { 3 | function testHD() public {} 4 | } -------------------------------------------------------------------------------- /test/samples/invalid/consts_unordered.invalid.sol: -------------------------------------------------------------------------------- 1 | /// #const uint256 X := Y * 100; 2 | /// #const uint256 Y := 5; 3 | contract InvalidConstantsOrder {} 4 | -------------------------------------------------------------------------------- /test/samples/invalid/deprecated_no_hash.warning.sol: -------------------------------------------------------------------------------- 1 | contract Foo { 2 | /// if_succeeds true; 3 | function foo() public {} 4 | } 5 | -------------------------------------------------------------------------------- /test/samples/invalid/deprecated_whitespace_natspec.warning.sol: -------------------------------------------------------------------------------- 1 | contract Foo { 2 | /// foobar @custom:scribble #if_succeeds true; 3 | function foo() public {} 4 | } 5 | -------------------------------------------------------------------------------- /test/samples/invalid/forall_iterator_type_incompatible.invalid.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.12; 2 | 3 | contract Foo { 4 | /// #if_succeeds forall(bytes32 x in hashes) x != bytes32(0x0); 5 | function foo(bytes32[] memory hashes) public {} 6 | } 7 | -------------------------------------------------------------------------------- /test/samples/invalid/forall_maps_aliasing1.invalid.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | contract BadAliasing { 4 | mapping(uint => uint) a; 5 | /// #if_succeeds forall (uint x in a) a[x] > 0; 6 | function main() public { 7 | mapping(uint => uint) storage p = a; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/samples/invalid/forall_maps_aliasing2.invalid.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | contract BadAliasing { 4 | struct S { 5 | mapping(uint => uint) a; 6 | mapping(uint => uint) b; 7 | } 8 | 9 | S s; 10 | /// #if_succeeds forall (uint x in s.a) s.a[x] > 0; 11 | function main() public { 12 | mapping(uint => uint) storage p = s.b; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/samples/invalid/garbage_at_start.warning.sol: -------------------------------------------------------------------------------- 1 | contract Foo { 2 | /// blah #if_succeeds true; 3 | function foo() public {} 4 | } 5 | -------------------------------------------------------------------------------- /test/samples/invalid/if_succeeds_on_free_function.invalid.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.7.5; 2 | 3 | /// #if_succeeds {:msg "Error"} true; 4 | function some() {} 5 | -------------------------------------------------------------------------------- /test/samples/invalid/if_updated_aliasing1.invalid.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | contract BadAliasing { 4 | //// #if_updated true; 5 | uint[] a; 6 | function main() public { 7 | uint[] storage p = a; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/samples/invalid/if_updated_aliasing2.invalid.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | contract BadAliasing { 4 | //// #if_updated true; 5 | uint[][] a; 6 | function main() public { 7 | uint[] storage p = a[0]; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/samples/invalid/if_updated_aliasing3.invalid.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | contract BadAliasing { 4 | //// #if_updated true; 5 | uint[] a1; 6 | uint[] a2; 7 | uint[] a3; 8 | function main(bool flag1, bool flag2) public { 9 | (uint[] storage p, uint x) = flag1 ? (a2, 1) : flag2 ? (a3, 2) : (a1, 3); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/samples/invalid/if_updated_aliasing4.invalid.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | abstract contract Base { 4 | constructor(uint[] storage s) { 5 | 6 | } 7 | } 8 | 9 | contract BadAliasing is Base { 10 | //// #if_updated true; 11 | uint[] a; 12 | 13 | constructor() Base(a) {} 14 | } 15 | -------------------------------------------------------------------------------- /test/samples/invalid/if_updated_aliasing5.invalid.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | abstract contract Base { 4 | constructor(uint[] storage s) { 5 | 6 | } 7 | } 8 | 9 | contract BadAliasing is Base(BadAliasing.a) { 10 | //// #if_updated true; 11 | uint[] a; 12 | 13 | constructor() {} 14 | } 15 | -------------------------------------------------------------------------------- /test/samples/invalid/if_updated_fun_return_ptr_bad.sol: -------------------------------------------------------------------------------- 1 | contract Foo { 2 | /// #if_updated arr.length > 0; 3 | uint[] arr; 4 | 5 | int8[] arr1; 6 | function getPtr() internal returns (int8[] storage) { 7 | return arr1; 8 | } 9 | 10 | function getPtr1() internal returns (uint[] storage) { 11 | return arr; 12 | } 13 | 14 | function main() { 15 | getPtr().push(0); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/samples/invalid/if_updated_length.invalid.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | contract LengthAssigned { 4 | //// #if_updated true; 5 | uint[] a; 6 | function main() public { 7 | a.length = 1; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/samples/invalid/if_updated_old_inline_initializer.invalid.sol: -------------------------------------------------------------------------------- 1 | contract Foo { 2 | /// #if_updated !(old(x) == 1); 3 | uint x = 1; 4 | } 5 | -------------------------------------------------------------------------------- /test/samples/invalid/if_updated_push_ref.invalid.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | contract PushRef { 4 | //// #if_updated true; 5 | uint[] a; 6 | function main() public { 7 | a.push() = 1; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/samples/invalid/immutables.sol: -------------------------------------------------------------------------------- 1 | /// #if_succeeds x == 5; 2 | contract Example01 { 3 | uint private immutable x; 4 | 5 | constructor() { 6 | x = 5; 7 | } 8 | } 9 | 10 | contract Example02 { 11 | uint private immutable x; 12 | 13 | /// #if_succeeds x == 5; 14 | constructor() { 15 | x = 5; 16 | } 17 | } 18 | 19 | /// #require x == 5; 20 | contract Example03 { 21 | uint private immutable x; 22 | 23 | constructor() { 24 | x = 5; 25 | } 26 | } 27 | 28 | contract Example04 { 29 | uint private immutable x; 30 | 31 | /// #require x == 5; 32 | constructor() { 33 | x = 5; 34 | } 35 | } 36 | 37 | 38 | -------------------------------------------------------------------------------- /test/samples/invalid/invalid_annotation.invalid.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.4; 2 | 3 | contract Foo { 4 | // Simple map 5 | uint[] a = [10]; 6 | int8[] b; 7 | 8 | /// @custom:scribble #if_succeeds unchecked_sum(a) > 10 && unchecked_sum(a) < 20 9 | /// dijfhs 10 | function pushA(uint k) public { 11 | a.push(k); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /test/samples/invalid/invariant_on_function.invalid.sol: -------------------------------------------------------------------------------- 1 | contract Some { 2 | /// #invariant {:msg "Error"} true; 3 | function other() public {} 4 | } 5 | -------------------------------------------------------------------------------- /test/samples/invalid/macro.bad_fun_arg_type.invalid.sol: -------------------------------------------------------------------------------- 1 | /// #macro foo(); 2 | contract Foo { 3 | function foo(uint x, int8 y) public {} 4 | } 5 | -------------------------------------------------------------------------------- /test/samples/invalid/macro.bad_schema1.invalid.yaml: -------------------------------------------------------------------------------- 1 | ownable: 2 | variables: 3 | _owner: 1 4 | properties: 5 | _owner: 6 | - msg: "can only be updated by an owner" 7 | prop: if_updated old(_owner) == msg.sender; 8 | -------------------------------------------------------------------------------- /test/samples/invalid/macro.empty.invalid.yaml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ConsenSysDiligence/scribble/8fef54864fa77527825714eab26d50b7823be4fa/test/samples/invalid/macro.empty.invalid.yaml -------------------------------------------------------------------------------- /test/samples/invalid/macro.good_fun_arg_type.sol: -------------------------------------------------------------------------------- 1 | /// #macro foo(); 2 | contract Foo { 3 | function foo(uint x, uint y) public {} 4 | } 5 | -------------------------------------------------------------------------------- /test/samples/invalid/macro.sem_error.invalid.yaml: -------------------------------------------------------------------------------- 1 | foo: 2 | variables: 3 | properties: 4 | foo(x,y): 5 | - msg: "dummy" 6 | prop: "#if_succeeds old(old(x))+y > 0;"; 7 | -------------------------------------------------------------------------------- /test/samples/invalid/macro.syntax_error.invalid.yaml: -------------------------------------------------------------------------------- 1 | !@#dqwlkm 2 | -------------------------------------------------------------------------------- /test/samples/invalid/macro.syntax_error1.invalid.yaml: -------------------------------------------------------------------------------- 1 | foo: 2 | variables: 3 | properties: 4 | foo(x,y): 5 | - msg: "dummy" 6 | prop: "#if_succeeds x+ > 0;"; 7 | -------------------------------------------------------------------------------- /test/samples/invalid/missing_terminator_semicolon.invalid.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | contract Test { 3 | /// Leading string 4 | /// 5 | /// #if_succeeds {:msg "P0"} y > x; 6 | /// 7 | /// #if_succeeds {:msg "P1"} 8 | /// y == x+2; 9 | /// 10 | /// #if_succeeds {:msg "P2"} y == x+3 11 | /// 12 | /// Trailing string 13 | function foo(uint256 x) public returns (uint256 y) { 14 | return x + 1; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/samples/invalid/ownable_macro.bad_var_type.invalid.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.0; 3 | 4 | /** 5 | * #macro ownable(owner); 6 | */ 7 | contract Ownable { 8 | uint public owner; 9 | 10 | function main() public { 11 | owner = 1; 12 | } 13 | } 14 | 15 | contract Test is Ownable {} 16 | -------------------------------------------------------------------------------- /test/samples/invalid/ownable_macro.no_var.invalid.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.0; 3 | 4 | /** 5 | * #macro ownable(owner1); 6 | */ 7 | contract Ownable { 8 | address public owner; 9 | 10 | event OwnershipTransferred(address indexed from, address indexed to); 11 | 12 | constructor() { 13 | transferOwnership(msg.sender); 14 | } 15 | 16 | modifier onlyOwner() { 17 | require(owner == msg.sender, "Ownable: message sender is not the current owner"); 18 | 19 | _; 20 | } 21 | 22 | function transferOwnership(address to) public virtual onlyOwner { 23 | address from = owner; 24 | 25 | owner = to; 26 | 27 | emit OwnershipTransferred(from, to); 28 | } 29 | } 30 | 31 | contract Test is Ownable {} 32 | -------------------------------------------------------------------------------- /test/samples/invalid/require.old.invalid.sol: -------------------------------------------------------------------------------- 1 | contract Foo { 2 | uint z; 3 | 4 | /// #require old(x) < 10; 5 | function bar(uint x) public { 6 | uint z = x + 1; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/samples/invalid/require.svar.invalid.sol: -------------------------------------------------------------------------------- 1 | contract Foo { 2 | /// #require z>1; 3 | uint z; 4 | 5 | function bar(uint x) public { 6 | uint z = x + 1; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/samples/invalid/try.old.invalid.sol: -------------------------------------------------------------------------------- 1 | contract Foo { 2 | uint z; 3 | 4 | 5 | /// #try old(x) < 10; 6 | function bar(uint x) public { 7 | uint z = x + 1; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/samples/invalid/try.svar.invalid.sol: -------------------------------------------------------------------------------- 1 | contract Foo { 2 | /// #try z>1; 3 | uint z; 4 | 5 | function bar(uint x) public { 6 | uint z = x + 1; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/samples/invalid/type_error.invalid.sol: -------------------------------------------------------------------------------- 1 | contract Foo { 2 | /// @custom:scribble #if_succeeds x > y; 3 | function bar(uint x, int y) public {} 4 | } 5 | -------------------------------------------------------------------------------- /test/samples/invalid/userDefinedTypesInFunction.invalid.sol: -------------------------------------------------------------------------------- 1 | /// SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.0; 3 | 4 | /** 5 | * #define isPolicyValid(Policy policy) bool = policy.exptime > 0 && policy.vfee > 0; 6 | */ 7 | contract Feature181 { 8 | struct Policy { 9 | bytes32 dn; 10 | uint exptime; 11 | uint vfee; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/samples/invariant_try_catch.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.15; 2 | 3 | interface Bar { 4 | function bar() external; 5 | } 6 | 7 | /// #invariant true; 8 | contract Foo { 9 | function main(bool flag, Bar b) internal { 10 | if (flag) 11 | try b.bar() { 12 | } catch Error(string memory reason) { 13 | revert(reason); 14 | } catch Panic(uint code) { 15 | revert("panic"); 16 | } catch { 17 | revert("foo"); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/samples/let_annotation.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.11; 2 | 3 | contract LetAnnotation { 4 | function foo(uint amount) public { 5 | uint[] memory a; 6 | for(uint i = 0; i < a.length; i++) { 7 | /// #let oldVal := a[i]; 8 | a[i] += amount; 9 | /// #assert oldVal > 0; 10 | 0; 11 | } 12 | } 13 | 14 | function foo1(uint amount) public { 15 | uint[] memory a; 16 | for(uint i = 0; i < a.length; i++) { 17 | /// #let oldVal := a[i]; 18 | /// #assert oldVal > 0; 19 | a[i] += amount; 20 | 0; 21 | } 22 | } 23 | 24 | function foo2(uint amount) public { 25 | uint[] memory a; 26 | /// #let oldVal := a[0]; 27 | for(uint i = 0; i < a.length; i++) { 28 | /// #assert oldVal > 0; 29 | a[i] += amount; 30 | } 31 | } 32 | 33 | /// #if_succeeds let y := bytes1(0xf) in y > 0x1; 34 | function foo3() public {} 35 | } 36 | 37 | // --------------------------------------------- 38 | 39 | contract Foo { 40 | function snd(uint v) internal pure returns (uint, uint) { 41 | return (1,v); 42 | } 43 | 44 | /// #if_succeeds {:msg "P0"} let _,x := snd(v) in x == 2; 45 | function foo(uint v) public { 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /test/samples/library_annotation.instrumented.sol: -------------------------------------------------------------------------------- 1 | /// This file is auto-generated by Scribble and shouldn't be edited directly. 2 | /// Use --disarm prior to make any changes. 3 | pragma solidity 0.8.19; 4 | 5 | library Foo { 6 | function foo() internal returns (uint RET_0) { 7 | RET_0 = _original_Foo_foo(); 8 | unchecked { 9 | if (!(RET_0 == 1)) { 10 | emit __ScribbleUtilsLib__22.AssertionFailed("000318:0066:000 0: "); 11 | assert(false); 12 | } 13 | } 14 | } 15 | 16 | function _original_Foo_foo() internal returns (uint) { 17 | return 1; 18 | } 19 | } 20 | 21 | contract Boo { 22 | function main() public { 23 | Foo.foo(); 24 | } 25 | } 26 | 27 | library __ScribbleUtilsLib__22 { 28 | event AssertionFailed(string message); 29 | 30 | event AssertionFailedData(int eventId, bytes encodingData); 31 | 32 | function assertionFailed(string memory arg_0) internal { 33 | emit AssertionFailed(arg_0); 34 | } 35 | 36 | function assertionFailedData(int arg_0, bytes memory arg_1) internal { 37 | emit AssertionFailedData(arg_0, arg_1); 38 | } 39 | 40 | function isInContract() internal returns (bool res) { 41 | assembly { 42 | res := sload(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c) 43 | } 44 | } 45 | 46 | function setInContract(bool v) internal { 47 | assembly { 48 | sstore(0x5f0b92cf9616afdee4f4136f66393f1343b027f01be893fa569eb2e2b667a40c, v) 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /test/samples/library_annotation.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.19; 2 | 3 | library Foo { 4 | /// #if_succeeds $result == 1; 5 | function foo() internal returns (uint) { 6 | return 1; 7 | } 8 | } 9 | 10 | contract Boo { 11 | function main() public { 12 | Foo.foo(); 13 | } 14 | } -------------------------------------------------------------------------------- /test/samples/macros/foo.scribble.yaml: -------------------------------------------------------------------------------- 1 | foo: 2 | variables: 3 | properties: 4 | foo(x,y): 5 | - msg: "dummy" 6 | prop: "#if_succeeds x+y > 0;"; 7 | -------------------------------------------------------------------------------- /test/samples/macros/myerc20.scribble.yaml: -------------------------------------------------------------------------------- 1 | myerc20: 2 | variables: 3 | bal: "mapping(address => uint256)" 4 | sup: "uint256" 5 | properties: 6 | : 7 | - msg: "Sum of balances is total supply" 8 | prop: "#invariant unchecked_sum(bal) == sup;" 9 | -------------------------------------------------------------------------------- /test/samples/misc_08.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.8; 2 | 3 | contract Errors { 4 | error E(); 5 | /// #if_succeeds true; 6 | function foo() public {} 7 | } 8 | 9 | // --------------------------------------------- 10 | 11 | contract RevertStmt { 12 | error E(); 13 | /// #if_succeeds false; 14 | function foo() public { 15 | revert E(); 16 | } 17 | } 18 | 19 | // --------------------------------------------- 20 | 21 | enum A { 22 | A, 23 | B, 24 | C 25 | } 26 | 27 | type Price is uint32; 28 | 29 | contract UserDefinedValueTypes { 30 | type Quantity is uint32; 31 | 32 | /// #if_succeeds Price.unwrap(p) * Quantity.unwrap(q) == Price.unwrap($result); 33 | function orderPrice(Price p, Quantity q) public returns (Price) { 34 | return Price.wrap(Price.unwrap(p) * Quantity.unwrap(q)); 35 | } 36 | } 37 | 38 | // --------------------------------------------- 39 | 40 | uint constant SOME = 10; 41 | 42 | function addSome(uint v) pure returns (uint) { 43 | return v + SOME; 44 | } 45 | 46 | contract FreeFuncs { 47 | uint num; 48 | 49 | /// #if_succeeds {:msg "P1"} num == 25; 50 | function operate() public { 51 | num = addSome(15); 52 | } 53 | } 54 | 55 | // --------------------------------------------- 56 | 57 | contract Foo { 58 | /// #if_succeeds old(1) > 0; 59 | function main() public {} 60 | } 61 | 62 | // --------------------------------------------- 63 | 64 | event X(uint a); 65 | 66 | contract Ev { 67 | /// #if_succeeds true; 68 | function main() public { 69 | emit X(1); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /test/samples/mixing_if_updated_and_forall.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.10; 2 | contract Foo { 3 | /// #if_updated forall(uint i in m) m[i] > 0; 4 | mapping(uint=>uint) m; 5 | 6 | /// #if_updated m1[address(0x0)]["abcd"] < 5; 7 | /// #if_assigned false; 8 | /// #if_assigned[addr] false; 9 | /// #if_assigned[addr][str] addr == address(0x0); 10 | mapping(address => mapping(string => uint)) m1; 11 | 12 | function assign_m(uint pos, uint v) public returns (uint) { 13 | m[pos] = v; 14 | return m[pos]; 15 | } 16 | 17 | /// #if_succeeds forall (address a in m1) forall (string memory s in m1[a]) m1[a][s] > 1; 18 | function assign_m1(address a, string memory s, uint v) public returns (uint) { 19 | m1[a][s] = v; 20 | return m1[a][s]; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /test/samples/mutability.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.6.10; 2 | contract Base { 3 | function getX() virtual view public returns (uint) { 4 | return 1; 5 | } 6 | } 7 | 8 | contract Foo is Base{ 9 | uint x = 1; 10 | 11 | /// #if_succeeds {:msg ""} x > 0; 12 | function getX() virtual view override public returns (uint) { 13 | return x; 14 | } 15 | } 16 | 17 | contract Child is Foo { 18 | function getX() virtual view override public returns (uint) { 19 | return x+1; 20 | } 21 | } 22 | 23 | /// #invariant {:msg ""} x > 0; 24 | contract Baz { 25 | uint x = 1; 26 | 27 | /// #if_succeeds {:msg ""} x > 0; 28 | function getX() view public returns (uint) { 29 | return x; 30 | } 31 | 32 | function getXPlus1() view public returns (uint) { 33 | return getX()+1; 34 | } 35 | 36 | /// #if_succeeds {:msg ""} x > 2; 37 | function getXPlus2() view public returns (uint) { 38 | return getXPlus1()+1; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /test/samples/ownable_macro.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity 0.8.10; 3 | 4 | /** 5 | * #macro ownable(owner); 6 | */ 7 | contract Ownable { 8 | address public owner; 9 | 10 | event OwnershipTransferred(address indexed from, address indexed to); 11 | 12 | constructor() { 13 | transferOwnership(msg.sender); 14 | } 15 | 16 | modifier onlyOwner() { 17 | require(owner == msg.sender, "Ownable: message sender is not the current owner"); 18 | 19 | _; 20 | } 21 | 22 | function transferOwnership(address to) public virtual onlyOwner { 23 | address from = owner; 24 | 25 | owner = to; 26 | 27 | emit OwnershipTransferred(from, to); 28 | } 29 | } 30 | 31 | contract Test is Ownable {} 32 | -------------------------------------------------------------------------------- /test/samples/skip_invariant_double_check.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.20; 2 | /** 3 | * The original constructor in this sample 4 | * SHOULD NOT be instrumented. 5 | * 6 | * See https://github.com/ConsenSys/scribble/issues/140 7 | */ 8 | 9 | /// #invariant true; 10 | contract Foo { 11 | 12 | /// #if_succeeds false; 13 | constructor(uint x) public {} 14 | } 15 | -------------------------------------------------------------------------------- /test/samples/solidity_builtins_08.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.8; 2 | 3 | enum A { 4 | A, 5 | B, 6 | C 7 | } 8 | 9 | type Price is uint32; 10 | 11 | interface IFace { 12 | function foo() external; 13 | } 14 | 15 | contract Boo { 16 | function foo() external {} 17 | } 18 | 19 | contract UserDefinedValueTypes { 20 | type Quantity is uint32; 21 | 22 | /// #if_succeeds a >= type(uint32).min && a <= type(uint32).max; 23 | /// #if_succeeds b >= type(int64).min && b <= type(int64).max; 24 | /// #if_succeeds c != type(A).min && c != type(A).max; 25 | /// #if_succeeds keccak256(bytes(type(IFace).name)) == keccak256(bytes("IFace")); 26 | /// #if_succeeds keccak256(type(Boo).creationCode) == bytes32(0x0); 27 | /// #if_succeeds keccak256(type(Boo).runtimeCode) == bytes32(0x0); 28 | /// #if_succeeds type(IFace).interfaceId != bytes4(0x0); 29 | function main(uint32 a, int64 b, A c) public { 30 | } 31 | } 32 | 33 | // --------------------------------------------- 34 | 35 | contract Foo { 36 | /// #if_succeeds abi.encode(v).length > 0; 37 | function foo(uint v) public { 38 | } 39 | 40 | /// #if_succeeds abi.encodePacked(v).length > 0; 41 | function foo1(uint v) public { 42 | } 43 | 44 | /// #if_succeeds abi.encodeWithSelector(bytes4(hex"01020304"), v).length > 0; 45 | function foo2(uint v) public { 46 | } 47 | 48 | /// #if_succeeds abi.encodeWithSignature("dummy", v).length > 0; 49 | function foo3(uint v) public { 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /test/samples/token_sale.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | // TokenSale (C) CaptureTheEther / Steve Marx 4 | 5 | contract TokenSale { 6 | mapping(address => uint256) public balanceOf; 7 | uint256 constant PRICE_PER_TOKEN = 1 ether; 8 | 9 | constructor() public payable { 10 | require(msg.value == 1 ether); 11 | } 12 | 13 | function isComplete() public view returns (bool) { 14 | return address(this).balance < 1 ether; 15 | } 16 | 17 | /// #if_succeeds {:msg "P0"} address(this).balance >= 1; 18 | function buy(uint256 numTokens) public payable { 19 | require(msg.value == numTokens * PRICE_PER_TOKEN); 20 | 21 | balanceOf[msg.sender] += numTokens; 22 | } 23 | 24 | /// #if_succeeds {:msg "P1"} address(this).balance >= 1; 25 | function sell(uint256 numTokens) public { 26 | require(balanceOf[msg.sender] >= numTokens); 27 | 28 | balanceOf[msg.sender] -= numTokens; 29 | msg.sender.transfer(numTokens * PRICE_PER_TOKEN); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /test/samples/unicode.sol: -------------------------------------------------------------------------------- 1 | /** 2 | * 😀😀😀😀😀😀😀 3 | * #invariant "😀😀😀😀😀😀😀" true; 4 | */ 5 | contract Foo { 6 | // 😀😀😀😀😀😀😀 7 | /** 8 | *😀😀😀😀😀😀😀 9 | * #if_succeeds "😀😀😀😀😀😀😀" true; 10 | */ 11 | function main() public { 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/samples/vm/assert_forall.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/assert.instrumented.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "AssertForAll", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "main", 23 | 24 | "args": { 25 | "types": ["uint[]"], 26 | "values": [[10, 99, 0, 11]] 27 | } 28 | }, 29 | { 30 | "act": "txCall", 31 | "user": "owner", 32 | "contract": "instance1", 33 | 34 | "method": "main", 35 | 36 | "args": { 37 | "types": ["uint[]"], 38 | "values": [[10, 99, 0, 11, 100]] 39 | }, 40 | "failure": "*" 41 | } 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /test/samples/vm/assert_fun_call.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/assert.instrumented.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "AssertFunCall", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "main", 23 | "returns": [], 24 | 25 | "args": { 26 | "types": ["uint", "uint", "uint"], 27 | "values": ["5", "6", "1"] 28 | } 29 | }, 30 | { 31 | "act": "txCall", 32 | "user": "owner", 33 | "contract": "instance1", 34 | 35 | "method": "main", 36 | "returns": [], 37 | 38 | "args": { 39 | "types": ["uint", "uint", "uint"], 40 | "values": ["5", "6", "2"] 41 | }, 42 | "failure": "*" 43 | } 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /test/samples/vm/calldata_parameters.instrumented.positive.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/calldata_paramteres.instrumented.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Test", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "moo" 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /test/samples/vm/calldata_parameters.positive.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/calldata_paramteres.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Test", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "moo" 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /test/samples/vm/contract_multi_args_debug.negative.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/contract_multi_arg_debug.instrumented.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Base", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "inc3", 23 | "returns": ["uint"], 24 | "logs": [["int", "bytes"], ["string"]], 25 | "args": { 26 | "types": ["uint"], 27 | "values": ["42"] 28 | }, 29 | "onLogs": [ 30 | [ 31 | "0", 32 | [ 33 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34 | 0, 0, 0, 0, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100 37 | ] 38 | ], 39 | ["000669:0066:000 0: "] 40 | ] 41 | } 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /test/samples/vm/contract_pos.instrumented.negative.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/contract_pos.instrumented.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Foo", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "fail", 23 | "logs": [["int", "bytes"], ["string"]], 24 | "onLogs": [ 25 | [ 26 | "0", 27 | [ 28 | 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29 | 0, 0, 0, 0, 0, 0, 0 30 | ] 31 | ], 32 | ["001629:0066:000 0: "] 33 | ] 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /test/samples/vm/contract_pos.instrumented.positive.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/contract_pos.instrumented.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Foo", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "inc", 23 | "onLogs": [] 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /test/samples/vm/contract_pos.negative.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/contract_pos.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Foo", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "fail" 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /test/samples/vm/contract_pos.positive.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/contract_pos.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Foo", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "inc" 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /test/samples/vm/contract_pos_constructor_fail.instrumented.negative.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/contract_pos_edge_cases.instrumented.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "PosConstructorFail", 14 | "user": "owner", 15 | "alias": "instance1", 16 | "failure": "*" 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /test/samples/vm/contract_pos_constructor_fail.negative.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/contract_pos_edge_cases.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "PosConstructorFail", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "inc" 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /test/samples/vm/contract_pos_ext_call_fail.instrumented.negative.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/contract_pos_edge_cases.instrumented.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "PosExtCallFail", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "fail", 23 | "failure": "*" 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /test/samples/vm/contract_pos_ext_call_fail.negative.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/contract_pos_edge_cases.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "PosExtCallFail", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "fail" 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /test/samples/vm/contract_pos_library_interface.instrumented.negative.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/contract_pos_edge_cases.instrumented.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "PosLibInterface", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "fail", 23 | "failure": "*" 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /test/samples/vm/contract_pos_library_interface.instrumented.positive.vm.json.disabled: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/contract_pos_edge_cases.instrumented.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "PosLibInterface", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "inc" 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /test/samples/vm/contract_pos_library_interface.negative.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/contract_pos_edge_cases.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "PosLibInterface", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "fail" 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /test/samples/vm/contract_pos_library_interface.positive.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/contract_pos_edge_cases.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "PosLibInterface", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "inc" 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /test/samples/vm/eq_encoded.instrumented.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/predefined.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "EqEncoded", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "positive", 23 | "returns": ["bool"], 24 | 25 | "args": { 26 | "types": [], 27 | "values": [] 28 | }, 29 | 30 | "onReturns": [ 31 | { 32 | "expect": true 33 | } 34 | ] 35 | }, 36 | { 37 | "act": "txCall", 38 | "user": "owner", 39 | "contract": "instance1", 40 | 41 | "method": "negative", 42 | "returns": ["bool"], 43 | 44 | "args": { 45 | "types": [], 46 | "values": [] 47 | }, 48 | 49 | "onReturns": [ 50 | { 51 | "expect": true 52 | } 53 | ] 54 | } 55 | ] 56 | } 57 | -------------------------------------------------------------------------------- /test/samples/vm/example_valentin.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/example_valentin.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "createUser", 13 | "alias": "other", 14 | "options": { 15 | "balance": 1e18 16 | } 17 | }, 18 | { 19 | "act": "deployContract", 20 | "contract": "FooToken", 21 | "user": "owner", 22 | "alias": "instance1" 23 | }, 24 | { 25 | "act": "staticCall", 26 | "user": "owner", 27 | "contract": "instance1", 28 | 29 | "method": "balanceOf", 30 | "returns": ["uint"], 31 | 32 | "args": { 33 | "types": ["address"], 34 | "values": [{ "alias": "owner" }] 35 | }, 36 | 37 | "onReturns": [ 38 | { 39 | "expect": "1000000" 40 | } 41 | ] 42 | } 43 | ] 44 | } 45 | -------------------------------------------------------------------------------- /test/samples/vm/if_updated_swap.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/if_updated_swap.instrumented.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "PointerSwap", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "main", 23 | 24 | "args": { 25 | "types": [], 26 | "values": [] 27 | } 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /test/samples/vm/increment.instrumented.positive.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/increment.instrumented.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Foo", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "foo", 23 | "returns": ["uint"], 24 | 25 | "args": { 26 | "types": ["uint"], 27 | "values": ["42"] 28 | }, 29 | "onReturns": [ 30 | { 31 | "expect": "43" 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /test/samples/vm/increment.positive.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/increment.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Foo", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "foo", 23 | "returns": ["uint"], 24 | 25 | "args": { 26 | "types": ["uint"], 27 | "values": ["42"] 28 | }, 29 | "onReturns": [ 30 | { 31 | "expect": "43" 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /test/samples/vm/increment_inherited.instrumented.positive.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/increment_inherited.instrumented.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Foo", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "foo", 23 | "returns": ["uint"], 24 | 25 | "args": { 26 | "types": ["uint"], 27 | "values": ["42"] 28 | }, 29 | "onReturns": [ 30 | { 31 | "expect": "43" 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /test/samples/vm/increment_inherited.positive.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/increment_inherited.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Foo", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "foo", 23 | "returns": ["uint"], 24 | 25 | "args": { 26 | "types": ["uint"], 27 | "values": ["42"] 28 | }, 29 | "onReturns": [ 30 | { 31 | "expect": "43" 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /test/samples/vm/increment_inherited2.instrumented.negative.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/increment_inherited2.instrumented.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Foo", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "foo", 23 | "returns": ["uint"], 24 | 25 | "args": { 26 | "types": ["uint"], 27 | "values": ["0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"] 28 | }, 29 | "failure": "*" 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /test/samples/vm/increment_inherited2.instrumented.positive.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/increment_inherited2.instrumented.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Foo", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "foo", 23 | "returns": ["uint"], 24 | 25 | "args": { 26 | "types": ["uint"], 27 | "values": ["42"] 28 | }, 29 | "onReturns": [ 30 | { 31 | "expect": "43" 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /test/samples/vm/increment_inherited2.negative.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/increment_inherited2.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Foo", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "foo", 23 | "returns": ["uint"], 24 | 25 | "args": { 26 | "types": ["uint"], 27 | "values": ["0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"] 28 | }, 29 | "onReturns": [ 30 | { 31 | "expect": "0" 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /test/samples/vm/increment_inherited2.positive.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/increment_inherited2.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Foo", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "foo", 23 | "returns": ["uint"], 24 | 25 | "args": { 26 | "types": ["uint"], 27 | "values": ["42"] 28 | }, 29 | "onReturns": [ 30 | { 31 | "expect": "43" 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /test/samples/vm/increment_inherited3.instrumented.negative.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/increment_inherited3.instrumented.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Foo", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "foo", 23 | "returns": ["uint"], 24 | 25 | "args": { 26 | "types": ["uint"], 27 | "values": ["0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"] 28 | }, 29 | "failure": "*" 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /test/samples/vm/increment_inherited3.instrumented.positive.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/increment_inherited3.instrumented.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Foo", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "foo", 23 | "returns": ["uint"], 24 | 25 | "args": { 26 | "types": ["uint"], 27 | "values": ["42"] 28 | }, 29 | "onReturns": [ 30 | { 31 | "expect": "43" 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /test/samples/vm/increment_inherited3.negative.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/increment_inherited3.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Foo", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "foo", 23 | "returns": ["uint"], 24 | 25 | "args": { 26 | "types": ["uint"], 27 | "values": ["0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"] 28 | }, 29 | "onReturns": [ 30 | { 31 | "expect": "0" 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /test/samples/vm/increment_inherited3.positive.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/increment_inherited3.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Foo", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "foo", 23 | "returns": ["uint"], 24 | 25 | "args": { 26 | "types": ["uint"], 27 | "values": ["42"] 28 | }, 29 | "onReturns": [ 30 | { 31 | "expect": "43" 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /test/samples/vm/increment_inherited3_v06.instrumented.negative.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/increment_inherited3_v06.instrumented.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Foo", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "foo", 23 | "returns": ["uint"], 24 | 25 | "args": { 26 | "types": ["uint"], 27 | "values": ["0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"] 28 | }, 29 | "failure": "*" 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /test/samples/vm/increment_inherited3_v06.instrumented.positive.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/increment_inherited3_v06.instrumented.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Foo", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "foo", 23 | "returns": ["uint"], 24 | 25 | "args": { 26 | "types": ["uint"], 27 | "values": ["42"] 28 | }, 29 | "onReturns": [ 30 | { 31 | "expect": "43" 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /test/samples/vm/increment_inherited3_v06.negative.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/increment_inherited3_v06.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Foo", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "foo", 23 | "returns": ["uint"], 24 | 25 | "args": { 26 | "types": ["uint"], 27 | "values": ["0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"] 28 | }, 29 | "onReturns": [ 30 | { 31 | "expect": "0" 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /test/samples/vm/increment_inherited3_v06.positive.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/increment_inherited3_v06.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Foo", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "foo", 23 | "returns": ["uint"], 24 | 25 | "args": { 26 | "types": ["uint"], 27 | "values": ["42"] 28 | }, 29 | "onReturns": [ 30 | { 31 | "expect": "43" 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /test/samples/vm/increment_inherited4.instrumented.negative.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/increment_inherited4.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Test", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "main", 23 | "fail": "*" 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /test/samples/vm/increment_inherited4.negative.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/increment_inherited4.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Test", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "main" 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /test/samples/vm/increment_inherited_collision.instrumented.positive.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/increment_inherited_collision.instrumented.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Foo", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "foo", 23 | "returns": ["uint"], 24 | 25 | "args": { 26 | "types": ["uint"], 27 | "values": ["42"] 28 | }, 29 | "onReturns": [ 30 | { 31 | "expect": "43" 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /test/samples/vm/increment_inherited_collision.positive.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/increment_inherited_collision.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Foo", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "foo", 23 | "returns": ["uint"], 24 | 25 | "args": { 26 | "types": ["uint"], 27 | "values": ["42"] 28 | }, 29 | "onReturns": [ 30 | { 31 | "expect": "43" 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /test/samples/vm/increment_inheritedv6.instrumented.positive.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/increment_inheritedv6.instrumented.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Foo", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "foo", 23 | "returns": ["uint"], 24 | 25 | "args": { 26 | "types": ["uint"], 27 | "values": ["42"] 28 | }, 29 | "onReturns": [ 30 | { 31 | "expect": "43" 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /test/samples/vm/increment_inheritedv6.positive.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/increment_inheritedv6.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Foo", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "foo", 23 | "returns": ["uint"], 24 | 25 | "args": { 26 | "types": ["uint"], 27 | "values": ["42"] 28 | }, 29 | "onReturns": [ 30 | { 31 | "expect": "43" 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /test/samples/vm/unnamed_lets.instrumented.negative.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/let_annotation.instrumented.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Foo", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "foo", 23 | "returns": ["uint"], 24 | 25 | "args": { 26 | "types": ["uint"], 27 | "values": ["3"] 28 | }, 29 | "failure": "*" 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /test/samples/vm/unnamed_lets.instrumented.positive.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/let_annotation.instrumented.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Foo", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "foo", 23 | "returns": ["uint"], 24 | 25 | "args": { 26 | "types": ["uint"], 27 | "values": ["2"] 28 | } 29 | } 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /test/samples/vm/unnamed_lets.negative.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/let_annotation.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Foo", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "foo", 23 | "returns": ["uint"], 24 | 25 | "args": { 26 | "types": ["uint"], 27 | "values": ["3"] 28 | } 29 | } 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /test/samples/vm/unnamed_lets.positive.vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "file": "test/samples/let_annotation.sol", 3 | "steps": [ 4 | { 5 | "act": "createUser", 6 | "alias": "owner", 7 | "options": { 8 | "balance": 1000e18 9 | } 10 | }, 11 | { 12 | "act": "deployContract", 13 | "contract": "Foo", 14 | "user": "owner", 15 | "alias": "instance1" 16 | }, 17 | { 18 | "act": "txCall", 19 | "user": "owner", 20 | "contract": "instance1", 21 | 22 | "method": "foo", 23 | "returns": ["uint"], 24 | 25 | "args": { 26 | "types": ["uint"], 27 | "values": ["2"] 28 | } 29 | } 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /test/unit/cha.spec.ts: -------------------------------------------------------------------------------- 1 | import { ASTReader, compileSol, ContractDefinition } from "solc-typed-ast"; 2 | import expect from "expect"; 3 | import { CHA, getCHA } from "../../src/instrumenter/cha"; 4 | 5 | describe("Contract hierarchy test", () => { 6 | let contracts: readonly ContractDefinition[]; 7 | let cha: CHA; 8 | 9 | before("CHA is built", async () => { 10 | const reader = new ASTReader(); 11 | const { data } = await compileSol("test/samples/cha.sol", "auto"); 12 | 13 | const units = reader.read(data); 14 | 15 | contracts = units.map((u) => u.vContracts).reduce((flat, next) => flat.concat(next), []); 16 | 17 | cha = getCHA(units); 18 | }); 19 | 20 | it("CHA is valid", () => { 21 | const [A, B, C, D, E] = contracts; 22 | 23 | expect(cha).toBeDefined(); 24 | 25 | expect(cha.roots).toEqual(new Set([A, C])); 26 | expect(cha.leaves).toEqual(new Set([D, E])); 27 | 28 | expect(cha.parents).toEqual( 29 | new Map([ 30 | [A, []], 31 | [B, [A]], 32 | [C, []], 33 | [D, [B, C]], 34 | [E, [B]] 35 | ]) 36 | ); 37 | 38 | expect(cha.children).toEqual( 39 | new Map([ 40 | [A, new Set([B])], 41 | [B, new Set([D, E])], 42 | [C, new Set([D])], 43 | [D, new Set([])], 44 | [E, new Set([])] 45 | ]) 46 | ); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /test/unit/utils.ts: -------------------------------------------------------------------------------- 1 | import { InferType, SourceUnit } from "solc-typed-ast"; 2 | import { ScribbleFactory, SourceMap } from "../../src"; 3 | import { getCallGraph } from "../../src/instrumenter/callgraph"; 4 | import { getCHA } from "../../src/instrumenter/cha"; 5 | import { 6 | AssertionMode, 7 | InstrumentationContext 8 | } from "../../src/instrumenter/instrumentation_context"; 9 | import { TypeEnv } from "../../src/spec-lang/tc"; 10 | import { SolFile } from "../../src/util/sources"; 11 | 12 | export function makeInstrumentationCtx( 13 | sources: SourceUnit[], 14 | factory: ScribbleFactory, 15 | files: Map, 16 | assertionMode: AssertionMode, 17 | compilerVersion: string 18 | ): InstrumentationContext { 19 | const inference = new InferType(compilerVersion); 20 | const srcFileMap: SourceMap = new Map( 21 | [...files.entries()].map(([name, contents]) => [name, new SolFile(name, contents)]) 22 | ); 23 | 24 | const ctx = new InstrumentationContext( 25 | factory, 26 | sources, 27 | assertionMode, 28 | assertionMode === "mstore", 29 | true, 30 | getCallGraph(inference, sources), 31 | getCHA(sources), 32 | {}, 33 | [], 34 | new Map(), 35 | srcFileMap, 36 | compilerVersion, 37 | false, 38 | "flat", 39 | new TypeEnv(inference), 40 | new Map(), 41 | [] 42 | ); 43 | 44 | return ctx; 45 | } 46 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2018", 4 | "module": "commonjs", 5 | "lib": ["es5", "es6", "esnext"], 6 | "declaration": true, 7 | "declarationMap": true, 8 | "sourceMap": true, 9 | "outDir": "dist", 10 | "removeComments": false, 11 | 12 | "strict": true, 13 | "noImplicitAny": true, 14 | "strictNullChecks": true, 15 | "strictFunctionTypes": true, 16 | "strictBindCallApply": true, 17 | "strictPropertyInitialization": true, 18 | "noImplicitThis": true, 19 | "alwaysStrict": true, 20 | 21 | "noUnusedLocals": true, 22 | "noImplicitReturns": true, 23 | 24 | "esModuleInterop": true, 25 | "forceConsistentCasingInFileNames": true, 26 | "resolveJsonModule": true 27 | }, 28 | "include": ["src/**/*"], 29 | "exclude": ["src/rewriter/import_directive_header.ts", "src/spec-lang/expr_parser_header.ts"] 30 | } 31 | --------------------------------------------------------------------------------