-
Notifications
You must be signed in to change notification settings - Fork 8
/
PauseHandlerFacet.sol
147 lines (128 loc) · 5.13 KB
/
PauseHandlerFacet.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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.18;
import "../../domain/BosonConstants.sol";
import { DiamondLib } from "../../diamond/DiamondLib.sol";
import "../../domain/BosonConstants.sol";
import { BosonTypes } from "../../domain/BosonTypes.sol";
import { ProtocolBase } from "../bases/OfferBase.sol";
import { ProtocolLib } from "../libs/ProtocolLib.sol";
import { IBosonPauseHandler } from "../../interfaces/handlers/IBosonPauseHandler.sol";
/**
* @title PauseHandlerFacet
*
* @notice Handles pausing all or part of the protocol.
*/
contract PauseHandlerFacet is ProtocolBase, IBosonPauseHandler {
/**
* @notice Initializes facet.
* This function is callable only once.
*/
function initialize() public onlyUninitialized(type(IBosonPauseHandler).interfaceId) {
DiamondLib.addSupportedInterface(type(IBosonPauseHandler).interfaceId);
}
/**
* @notice Pauses some or all of the protocol.
*
* Emits a ProtocolPaused event if successful.
*
* Reverts if:
* - Caller does not have PAUSER role
* - A region is specified more than once
*
* @param _regions - an array of regions to pause. See: {BosonTypes.PausableRegion}
*/
function pause(BosonTypes.PausableRegion[] calldata _regions) external onlyRole(PAUSER) nonReentrant {
togglePause(_regions, true);
// Notify watchers of state change
emit ProtocolPaused(_regions, msgSender());
}
/**
* @notice Unpauses the protocol.
*
* Emits a ProtocolUnpaused event if successful.
*
* Reverts if:
* - Caller does not have PAUSER role
* - Protocol is not currently paused
* - A region is specified more than once
*/
function unpause(BosonTypes.PausableRegion[] calldata _regions) external onlyRole(PAUSER) nonReentrant {
// Cache protocol status for reference
ProtocolLib.ProtocolStatus storage status = protocolStatus();
// Make sure the protocol is paused
require(status.pauseScenario > 0, NOT_PAUSED);
togglePause(_regions, false);
// Notify watchers of state change
emit ProtocolUnpaused(_regions, msgSender());
}
/**
* @notice Returns the regions paused
*
* @return regions - an array of regions that are currently paused. See: {BosonTypes.PausableRegion}
*/
function getPausedRegions() external view returns (BosonTypes.PausableRegion[] memory regions) {
// Cache protocol status for reference
ProtocolLib.ProtocolStatus storage status = protocolStatus();
uint256 totalRegions = uint256(type(BosonTypes.PausableRegion).max);
regions = new BosonTypes.PausableRegion[](totalRegions);
// Return all regions if all are paused.
if (status.pauseScenario == ALL_REGIONS_MASK) {
for (uint256 i = 0; i < totalRegions; i++) {
regions[i] = BosonTypes.PausableRegion(i);
}
} else {
uint256 count = 0;
for (uint256 i = 0; i < totalRegions; i++) {
// Check if the region is paused by bitwise AND operation with shifted 1
if ((status.pauseScenario & (1 << i)) != 0) {
regions[count] = BosonTypes.PausableRegion(i);
count++;
}
}
// setting the correct number of regions
assembly {
mstore(regions, count)
}
}
}
/**
* @notice Toggles pause/unpause for some or all of the protocol.
*
* Toggle all regions if none are specified.
*
* Reverts if:
* - A region is specified more than once
*
* @param _regions - an array of regions to pause/unpause. See: {BosonTypes.PausableRegion}
* @param _pause - a boolean indicating whether to pause (true) or unpause (false)
*/
function togglePause(BosonTypes.PausableRegion[] calldata _regions, bool _pause) internal {
// Cache protocol status for reference
ProtocolLib.ProtocolStatus storage status = protocolStatus();
// Toggle all regions if none are specified.
if (_regions.length == 0) {
// Store the toggle scenario
status.pauseScenario = _pause ? ALL_REGIONS_MASK : 0;
return;
}
uint256 region;
uint256 incomingScenario;
// Calculate the incoming scenario as the sum of individual regions
// Use "or" to get the correct value even if the same region is specified more than once
for (uint256 i = 0; i < _regions.length; i++) {
// Get enum value as power of 2
region = 1 << uint256(_regions[i]);
incomingScenario |= region;
}
// Store the toggle scenario
if (_pause) {
// for pausing, just "or" the incoming scenario with the existing one
// equivalent to summation
status.pauseScenario |= incomingScenario;
} else {
// for unpausing, "and" the inverse of the incoming scenario with the existing one
// equivalent to subtraction
status.pauseScenario &= ~incomingScenario;
}
}
}