/
Host.sol
185 lines (161 loc) · 7.31 KB
/
Host.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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.7;
import { AddressStorage } from "../../contracts/AddressStorage.sol";
// import {
// AddressStorage
// } from "@solidity-utilities/address-storage/contracts/AddressStorage.sol";
import { InterfaceAddressStorage } from "../../contracts/InterfaceAddressStorage.sol";
// import {
// InterfaceAddressStorage
// } from "@solidity-utilities/address-storage/contracts/InterfaceAddressStorage.sol";
import { Account } from "./Account.sol";
/// @title Example contract to demonstrate further abstraction of `AddressStorage` features
/// @author S0AndS0
contract Host {
address public active_accounts = address(new AddressStorage(address(this)));
address public banned_accounts = address(new AddressStorage(address(this)));
address public owner;
/* -------------------------------------------------------------------- */
///
constructor(address _owner) {
owner = _owner;
}
/* -------------------------------------------------------------------- */
/// @notice Require message sender to be an instance owner
/// @param _caller {string} Function name that implements this modifier
modifier onlyOwner(string memory _caller) {
string memory _message = string(
abi.encodePacked("Host.", _caller, ": message sender not an owner")
);
require(msg.sender == owner, _message);
_;
}
/// @notice Require `_key` to not be stored by `active_accounts`
/// @param _key **{address}** Reference to `Account.owner`
modifier onlyNotActive(address _key, string memory _caller) {
string memory _message = string(
abi.encodePacked("Host.", _caller, ": account already active")
);
require(!InterfaceAddressStorage(active_accounts).has(_key), _message);
_;
}
/// @notice Require `_key` to not be stored by `banned_accounts`
/// @param _key **{address}** Reference to `Account.owner`
modifier onlyNotBanned(address _key, string memory _caller) {
string memory _message = string(
abi.encodePacked("Host.", _caller, ": account was banned")
);
require(!InterfaceAddressStorage(banned_accounts).has(_key), _message);
_;
}
/* -------------------------------------------------------------------- */
///
event ActivatedAccount(address owner, address account_reference);
///
event BannedAccount(address owner, address account_reference);
/* -------------------------------------------------------------------- */
/// @notice Move `Account` reference from `active_accounts` to `banned_accounts`
/// @param _key **{address}** Key within `active_accounts` to ban
/// @custom:throws `"Host.banAccount: not active"`
/// @custom:throws `"Host.banAccount: already banned"`
function banAccount(address _key) external onlyOwner("banAccount") {
address _account_reference = InterfaceAddressStorage(active_accounts)
.removeOrError(_key, "Host.banAccount: not active");
InterfaceAddressStorage(banned_accounts).setOrError(
_key,
_account_reference,
"Host.banAccount: already banned"
);
emit BannedAccount(_key, _account_reference);
}
/// @notice Add existing `Account` instance to `active_accounts`
/// @param **{Account}** Previously deployed `Account` contract instance
/// @return **{Account}** Instance of `Account`
/// @custom:throws `"Host.importAccount: account already active"`
/// @custom:throws `"Host.importAccount: account was banned"`
function importAccount(Account _account)
public
onlyNotActive(_account.owner(), "importAccount")
onlyNotBanned(_account.owner(), "importAccount")
returns (Account)
{
address _owner = _account.owner();
address _account_reference = address(_account);
InterfaceAddressStorage(active_accounts).set(
_owner,
_account_reference
);
emit ActivatedAccount(_owner, _account_reference);
return _account;
}
/// @notice Initialize new instance of `Account` and add to `active_accounts`
/// @param _owner **{address}** Account owner to assign
/// @param _name **{string}** Account name to assign
/// @return **{Account}** Instance of `Account` with given `owner` and `name`
/// @custom:throws `"Host.registerAccount: account already active"`
/// @custom:throws `"Host.registerAccount: account was banned"`
function registerAccount(address _owner, string memory _name)
external
onlyNotActive(_owner, "registerAccount")
onlyNotBanned(_owner, "registerAccount")
returns (Account)
{
Account _account = new Account(_owner, _name);
address _account_reference = address(_account);
InterfaceAddressStorage(active_accounts).set(
_owner,
_account_reference
);
emit ActivatedAccount(_owner, _account_reference);
return _account;
}
/// @notice Delete reference from either `active_accounts` or `banned_accounts`
/// @param _key **{address}** Owner of `Account` instance to remove
/// @return **{Account}** Instance from removed value `address`
/// @custom:throws `"Host.removeAccount: message sender not an owner"`
/// @custom:throws `"Host.removeAccount: account not available"`
function removeAccount(address _key)
external
onlyOwner("removeAccount")
returns (Account)
{
address _account_reference;
if (InterfaceAddressStorage(active_accounts).has(_key)) {
_account_reference = InterfaceAddressStorage(active_accounts)
.remove(_key);
} else if (InterfaceAddressStorage(banned_accounts).has(_key)) {
_account_reference = InterfaceAddressStorage(banned_accounts)
.remove(_key);
}
require(
_account_reference != address(0x0),
"Host.removeAccount: account not available"
);
return Account(_account_reference);
}
/// @notice Sync `active_accounts` key with `Account.owner`
/// @dev Account instance should update `owner` before calling this method
/// @param _key **{address}** Old owner `address` to sync with `Account.owner`
/// @custom:throws **{Error}** `"Host.updateKey: message sender not Account owner"`
function updateKey(address _key) external {
Account _account = Account(
InterfaceAddressStorage(active_accounts).get(_key)
);
require(
msg.sender == _account.owner(),
"Host.updateKey: message sender not Account owner"
);
InterfaceAddressStorage(active_accounts).remove(_key);
importAccount(_account);
}
/// @notice Retrieve `Account.name` for given `_key`
/// @param _key **{address}** Owner of `active_accounts` instance
/// @return **{string}** Name saved within `Account` instance
/// @custom:throws **{Error}** `"Host.whoIs: account not active"`
function whoIs(address _key) external view returns (string memory) {
address _account_reference = InterfaceAddressStorage(active_accounts)
.getOrError(_key, "Host.whoIs: account not active");
Account _account_instance = Account(_account_reference);
return _account_instance.name();
}
}