-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAssertion.sol
More file actions
81 lines (71 loc) · 3.76 KB
/
Assertion.sol
File metadata and controls
81 lines (71 loc) · 3.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import {Credible} from "./Credible.sol";
import {TriggerRecorder} from "./TriggerRecorder.sol";
import {SpecRecorder, AssertionSpec} from "./SpecRecorder.sol";
import {StateChanges} from "./StateChanges.sol";
/// @title Assertion
/// @author Phylax Systems
/// @notice Base contract for creating Credible Layer assertions
/// @dev Inherit from this contract to create custom assertions. Assertions can inspect
/// transaction state via the inherited `ph` precompile and register triggers to specify
/// when the assertion should be executed.
///
/// Example:
/// ```solidity
/// contract MyAssertion is Assertion {
/// function triggers() external view override {
/// registerCallTrigger(this.checkInvariant.selector, ITarget.deposit.selector);
/// }
///
/// function checkInvariant() external {
/// ph.forkPostTx();
/// // Check invariants...
/// }
/// }
/// ```
abstract contract Assertion is Credible, StateChanges {
/// @notice The trigger recorder precompile for registering assertion triggers
/// @dev Address is derived from a deterministic hash for consistency
TriggerRecorder constant triggerRecorder = TriggerRecorder(address(uint160(uint256(keccak256("TriggerRecorder")))));
/// @notice The spec recorder precompile for registering the assertion spec
/// @dev Address is derived from keccak256("SpecRecorder")
SpecRecorder constant specRecorder = SpecRecorder(address(uint160(uint256(keccak256("SpecRecorder")))));
/// @notice Used to record fn selectors and their triggers.
function triggers() external view virtual;
/// @notice Registers a call trigger for the AA without specifying an AA function selector.
/// This will trigger the assertion function on any call to the AA.
/// @param fnSelector The function selector of the assertion function.
function registerCallTrigger(bytes4 fnSelector) internal view {
triggerRecorder.registerCallTrigger(fnSelector);
}
/// @notice Registers a call trigger for calls to the AA with a specific AA function selector.
/// @param fnSelector The function selector of the assertion function.
/// @param triggerSelector The function selector upon which the assertion will be triggered.
function registerCallTrigger(bytes4 fnSelector, bytes4 triggerSelector) internal view {
triggerRecorder.registerCallTrigger(fnSelector, triggerSelector);
}
/// @notice Registers storage change trigger for any slot
/// @param fnSelector The function selector of the assertion function.
function registerStorageChangeTrigger(bytes4 fnSelector) internal view {
triggerRecorder.registerStorageChangeTrigger(fnSelector);
}
/// @notice Registers storage change trigger for a specific slot
/// @param fnSelector The function selector of the assertion function.
/// @param slot The storage slot to trigger on.
function registerStorageChangeTrigger(bytes4 fnSelector, bytes32 slot) internal view {
triggerRecorder.registerStorageChangeTrigger(fnSelector, slot);
}
/// @notice Registers balance change trigger for the AA
/// @param fnSelector The function selector of the assertion function.
function registerBalanceChangeTrigger(bytes4 fnSelector) internal view {
triggerRecorder.registerBalanceChangeTrigger(fnSelector);
}
/// @notice Registers the desired assertion spec. Must be called within the constructor.
/// The assertion spec defines what subset of precompiles are available.
/// Can only be called once. For an assertion to be valid, it needs a defined spec.
/// @param spec The desired AssertionSpec.
function registerAssertionSpec(AssertionSpec spec) internal view {
specRecorder.registerAssertionSpec(spec);
}
}