This repository has been archived by the owner on Dec 7, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 16
/
CombineTier.sol
97 lines (88 loc) · 3.41 KB
/
CombineTier.sol
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
// SPDX-License-Identifier: CAL
pragma solidity =0.8.10;
import "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import {RainVM, State} from "../vm/RainVM.sol";
import {VMState, StateConfig} from "../vm/libraries/VMState.sol";
import {BlockOps} from "../vm/ops/BlockOps.sol";
import {TierOps} from "../vm/ops/TierOps.sol";
import {TierwiseCombine} from "./libraries/TierwiseCombine.sol";
import {ReadOnlyTier, ITier} from "./ReadOnlyTier.sol";
/// @title CombineTier
/// @notice Implements `ReadOnlyTier` over RainVM. Allows combining the reports
/// from any other `ITier` contracts referenced in the `ImmutableSource` set at
/// construction.
/// The value at the top of the stack after executing the rain script will be
/// used as the return of `report`.
contract CombineTier is ReadOnlyTier, RainVM, Initializable {
/// @dev local opcode to put tier report account on the stack.
uint256 private constant ACCOUNT = 0;
/// @dev local opcodes length.
uint256 internal constant LOCAL_OPS_LENGTH = 1;
/// @dev local offset for block ops.
uint256 private immutable blockOpsStart;
/// @dev local offset for tier ops.
uint256 private immutable tierOpsStart;
/// @dev local offset for combine tier ops.
uint256 private immutable localOpsStart;
address private vmStatePointer;
constructor() {
/// These local opcode offsets are calculated as immutable but are
/// really just compile time constants. They only depend on the
/// imported libraries and contracts. These are calculated at
/// construction to future-proof against underlying ops being
/// added/removed and potentially breaking the offsets here.
blockOpsStart = RainVM.OPS_LENGTH;
tierOpsStart = blockOpsStart + BlockOps.OPS_LENGTH;
localOpsStart = tierOpsStart + TierOps.OPS_LENGTH;
}
function initialize(StateConfig memory config_) external initializer {
vmStatePointer = VMState.snapshot(VMState.newState(config_));
}
/// @inheritdoc RainVM
function applyOp(
bytes memory context_,
State memory state_,
uint256 opcode_,
uint256 operand_
) internal view override {
unchecked {
if (opcode_ < tierOpsStart) {
BlockOps.applyOp(
context_,
state_,
opcode_ - blockOpsStart,
operand_
);
} else if (opcode_ < localOpsStart) {
TierOps.applyOp(
context_,
state_,
opcode_ - tierOpsStart,
operand_
);
} else {
opcode_ -= localOpsStart;
require(opcode_ < LOCAL_OPS_LENGTH, "MAX_OPCODE");
if (opcode_ == ACCOUNT) {
address account_ = abi.decode(context_, (address));
state_.stack[state_.stackIndex] = uint256(
uint160(account_)
);
state_.stackIndex++;
}
}
}
}
/// @inheritdoc ITier
function report(address account_)
external
view
virtual
override
returns (uint256)
{
State memory state_ = VMState.restore(vmStatePointer);
eval(abi.encode(account_), state_, 0);
return state_.stack[state_.stackIndex - 1];
}
}