-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathWebContract.sol
More file actions
235 lines (199 loc) · 8.46 KB
/
Copy pathWebContract.sol
File metadata and controls
235 lines (199 loc) · 8.46 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
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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.20;
import "./TokenManager.sol";
/// @title WebContract
/// @notice This contract provides functionality for managing web resources, admin roles, and various token operations
/// @dev Inherits from Ownable and implements additional features like locking, admin management, and resource handling
abstract contract WebContract is TokenManager {
/// @notice Represents the version of the contract
/// @dev Used to track major, minor, and patch versions
struct Version {
uint256 majorVersion;
uint256 minorVersion;
uint256 patchVersion;
}
uint256 private immutable MAJOR_VERSION = 1;
uint256 private immutable MINOR_VERSION = 1;
uint256 private immutable PATCH_VERSION = 1;
/// @notice Returns the current version of the web contract
/// @return Version struct containing major, minor, and patch versions
function webContractVersion() public pure returns (Version memory) {
return Version(MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION);
}
/// @notice Struct to hold redirect information
struct RedirectInfo {
string redirectValue; // The actual redirect value (hash, chain ID, etc.)
string redirectType; // e.g., "ipfs", 137, "pol", 1, "eth", "ordinal", or "" for no redirect
uint8 redirectCode; // Similar to 301, 302 etc. None (0), permanent (1) or temporary (2) using uint8 allows for future expansion
}
/// @notice The redirect information for the contract
RedirectInfo private redirectInfo;
/// @notice Sets the redirect information
/// @param _type The type of redirect (e.g., "ipfs", [chainId], [chainAlias], "ordinal", or "" for no redirect)
/// @param _value The redirect value (e.g., IPFS hash, address, ordinal ID)
/// @dev Can only be called by the contract owner
function setRedirect(
string memory _value,
string memory _type,
uint8 _code
) public virtual onlyAdmin notLocked {
redirectInfo = RedirectInfo(_value, _type, _code);
emit RedirectSet(_value, _type, _code);
}
/// @notice Gets the current redirect information
/// @return RedirectInfo struct containing the redirect type and value
function getRedirect() public view virtual returns (RedirectInfo memory) {
return
redirectInfo.redirectCode > 0
? RedirectInfo(
string.concat("redirect/", redirectInfo.redirectType),
redirectInfo.redirectValue,
redirectInfo.redirectCode
)
: redirectInfo;
}
/// @notice Whether the contract is locked or immutable
bool private writeLocked;
bool private writeImmutable;
/// @notice Checks if the contract is currently locked
/// @return bool indicating whether the contract is locked
function isLocked() public view returns (bool) {
return writeLocked;
}
function isImmutable() public view returns (bool) {
return writeImmutable;
}
/// @notice Modifier to ensure function can only be called when contract is not locked or immutable
modifier notLocked() {
require(!writeLocked && !writeImmutable, "Contract is locked");
_;
}
/// @notice Locks the contract, preventing certain operations
/// @dev Can only be called by the owner when the contract is not locked
function lockContract() public virtual notLocked onlyOwner {
writeLocked = true;
emit ContractLocked();
}
/// @notice Unlocks the contract
/// @dev Can only be called by the owner
function unlockContract() public virtual onlyOwner {
writeLocked = false;
emit ContractUnlocked();
}
/// @notice Makes the contract immutable, permanently locking it
/// @dev Can only be called by the owner, cannot be undone!
function makeImmutable() public virtual onlyOwner {
writeImmutable = true;
emit ContractMadeImmutable();
}
mapping(address => bool) private admins;
/// @notice Modifier to restrict function access to admins or the owner
modifier onlyAdmin() {
require(msg.sender == owner() || admins[msg.sender], "Not an admin");
_;
}
/// @notice Adds a new admin
/// @param _admin Address of the new admin
/// @dev Can only be called by the owner
/// @dev SECURITY WARNING: Overriding this function may break access control.
/// Ensure any override maintains the intended admin addition logic.
function addAdmin(address _admin) public virtual onlyOwner {
admins[_admin] = true;
emit AdminAdded(_admin);
}
/// @notice Removes an admin
/// @param _admin Address of the admin to remove
/// @dev Can only be called by the owner
/// @dev SECURITY WARNING: Overriding this function may break access control.
/// Ensure any override maintains the intended admin removal logic.
function removeAdmin(address _admin) public virtual onlyOwner {
admins[_admin] = false;
emit AdminRemoved(_admin);
}
/// @notice Checks if an address is an admin
/// @param _admin Address to check
/// @return bool indicating whether the address is an admin
/// @dev SECURITY WARNING: Overriding this function may break access control.
/// Ensure any override maintains the intended admin verification logic.
function _isAdmin(address _admin) internal view virtual returns (bool) {
return _admin == owner() || admins[_admin];
}
/// @notice Contract constructor
/// @param _owner Address of the initial owner
constructor(address _owner) TokenManager(_owner) {}
/// @notice Represents a resource file with content chunks and content type
struct ResourceFile {
bytes content;
string contentType;
uint8 redirectCode;
}
mapping(string => ResourceFile) private resourceFiles;
/// @notice Sets a chunk of a resource file
/// @param _path Path of the resource
/// @param _content Content of the chunk
/// @param _contentType Content type of the resource
/// @param _replace Replace or concat the resource
function setResource(
string calldata _path,
bytes calldata _content,
string calldata _contentType,
bool _replace,
uint8 _redirectCode
) public virtual onlyAdmin notLocked {
ResourceFile storage file = resourceFiles[_path];
require(bytes(_contentType).length > 0, "Content type is required");
if (
keccak256(abi.encode(_contentType)) !=
keccak256(abi.encode(file.contentType))
) {
file.contentType = _contentType;
}
if (_redirectCode != file.redirectCode) {
file.redirectCode = _redirectCode;
}
if (_replace) {
// If the contentType is not set, this is a new file
file.content = _content;
} else {
file.content = abi.encodePacked(file.content, _content);
}
}
/// @notice Retrieves a chunk of a resource file
/// @param path Path of the resource
/// @return bytes memory, string memory The content chunk and content type
function getResource(
string memory path
) public view virtual returns (bytes memory, string memory) {
ResourceFile memory file = resourceFiles[path];
return (file.content, file.contentType);
}
/// @notice Removes a resource
/// @param path Path of the resource to remove
/// @dev Can only be called by an admin when the contract is not locked
function removeResource(
string memory path
) public virtual onlyAdmin notLocked {
delete resourceFiles[path];
emit ResourceRemoved(path);
}
/// @dev Emitted when the redirect information is set
event RedirectSet(
string redirectValue,
string redirectType,
uint8 redirectCode
);
/// @dev Emitted when the contract is locked
event ContractLocked();
/// @dev Emitted when the contract is unlocked
event ContractUnlocked();
/// @dev Emitted when the contract is made immutable
event ContractMadeImmutable();
/// @dev Emitted when an admin is added
event AdminAdded(address admin);
/// @dev Emitted when an admin is removed
event AdminRemoved(address admin);
/// @dev Emitted when a resource chunk is set
event ResourceChunkSet(string path, uint256 chunkIndex);
/// @dev Emitted when a resource is removed
event ResourceRemoved(string path);
}