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
/
ReadWriteTier.sol
98 lines (88 loc) · 3.37 KB
/
ReadWriteTier.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
// SPDX-License-Identifier: CAL
pragma solidity =0.8.10;
import {ITier} from "./ITier.sol";
import "./libraries/TierConstants.sol";
import "./libraries/TierReport.sol";
/// @title ReadWriteTier
/// @notice `ReadWriteTier` is a base contract that other contracts are
/// expected to inherit.
///
/// It handles all the internal accounting and state changes for `report`
/// and `setTier`.
///
/// It calls an `_afterSetTier` hook that inheriting contracts can override to
/// enforce tier requirements.
///
/// @dev ReadWriteTier can `setTier` in addition to generating reports.
/// When `setTier` is called it automatically sets the current blocks in the
/// report for the new tiers. Lost tiers are scrubbed from the report as tiered
/// addresses move down the tiers.
contract ReadWriteTier is ITier {
/// account => reports
mapping(address => uint256) private reports;
/// Either fetch the report from storage or return UNINITIALIZED.
/// @inheritdoc ITier
function report(address account_)
public
view
virtual
override
returns (uint256)
{
// Inequality here to silence slither warnings.
return
reports[account_] > 0
? reports[account_]
: TierConstants.NEVER_REPORT;
}
/// Errors if the user attempts to return to the ZERO tier.
/// Updates the report from `report` using default `TierReport` logic.
/// Calls `_afterSetTier` that inheriting contracts SHOULD
/// override to enforce status requirements.
/// Emits `TierChange` event.
/// @inheritdoc ITier
function setTier(
address account_,
uint256 endTier_,
bytes calldata data_
) external virtual override {
// The user must move to at least tier 1.
// The tier 0 status is reserved for users that have never
// interacted with the contract.
require(endTier_ > 0, "SET_ZERO_TIER");
uint256 report_ = report(account_);
uint256 startTier_ = TierReport.tierAtBlockFromReport(
report_,
block.number
);
reports[account_] = TierReport.updateReportWithTierAtBlock(
report_,
startTier_,
endTier_,
block.number
);
// Emit this event for ITier.
emit TierChange(msg.sender, account_, startTier_, endTier_, data_);
// Call the `_afterSetTier` hook to allow inheriting contracts
// to enforce requirements.
// The inheriting contract MUST `require` or otherwise
// enforce its needs to rollback a bad status change.
_afterSetTier(account_, startTier_, endTier_, data_);
}
/// Inheriting contracts SHOULD override this to enforce requirements.
///
/// All the internal accounting and state changes are complete at
/// this point.
/// Use `require` to enforce additional requirements for tier changes.
///
/// @param account_ The account with the new tier.
/// @param startTier_ The tier the account had before this update.
/// @param endTier_ The tier the account will have after this update.
/// @param data_ Additional arbitrary data to inform update requirements.
function _afterSetTier(
address account_,
uint256 startTier_,
uint256 endTier_,
bytes calldata data_
) internal virtual {} // solhint-disable-line no-empty-blocks
}