-
Notifications
You must be signed in to change notification settings - Fork 0
/
Base.sol
100 lines (81 loc) · 3.41 KB
/
Base.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
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.18;
import {ISafeProtocolPlugin} from "@safe-global/safe-core-protocol/contracts/interfaces/Integrations.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
enum MetadataProviderType {
IPFS,
URL,
Contract,
Event
}
interface IMetadataProvider {
function retrieveMetadata(bytes32 metadataHash) external view returns (bytes memory metadata);
}
struct PluginMetadata {
string name;
string version;
bool requiresRootAccess;
string iconUrl;
string appUrl;
bool hook;
}
library PluginMetadataOps {
function encode(PluginMetadata memory data) internal pure returns (bytes memory) {
return
abi.encodePacked(
uint8(0x00), // Format
uint8(0x00), // Format version
abi.encode(data.name, data.version, data.requiresRootAccess, data.iconUrl, data.appUrl, data.hook) // Plugin Metadata
);
}
function decode(bytes calldata data) internal pure returns (PluginMetadata memory) {
require(bytes16(data[0:2]) == bytes16(0x0000), "Unsupported format or format version");
(string memory name, string memory version, bool requiresRootAccess, string memory iconUrl, string memory appUrl, bool hook) = abi.decode(
data[2:],
(string, string, bool, string, string, bool)
);
return PluginMetadata(name, version, requiresRootAccess, iconUrl, appUrl, hook);
}
}
abstract contract BasePlugin is ISafeProtocolPlugin {
using PluginMetadataOps for PluginMetadata;
string public name;
string public version;
bool public immutable requiresRootAccess;
bytes32 public immutable metadataHash;
constructor(PluginMetadata memory metadata) {
name = metadata.name;
version = metadata.version;
requiresRootAccess = metadata.requiresRootAccess;
metadataHash = keccak256(metadata.encode());
}
function supportsInterface(bytes4 interfaceId) external view returns (bool) {
return interfaceId == type(ISafeProtocolPlugin).interfaceId || interfaceId == type(IERC165).interfaceId;
}
}
abstract contract BasePluginWithStoredMetadata is BasePlugin, IMetadataProvider {
using PluginMetadataOps for PluginMetadata;
bytes private encodedMetadata;
constructor(PluginMetadata memory metadata) BasePlugin(metadata) {
encodedMetadata = metadata.encode();
}
function retrieveMetadata(bytes32 _metadataHash) external view override returns (bytes memory metadata) {
require(metadataHash == _metadataHash, "Cannot retrieve metadata");
return encodedMetadata;
}
function metadataProvider() public view override returns (uint256 providerType, bytes memory location) {
providerType = uint256(MetadataProviderType.Contract);
location = abi.encode(address(this));
}
}
abstract contract BasePluginWithEventMetadata is BasePlugin {
using PluginMetadataOps for PluginMetadata;
event Metadata(bytes32 indexed metadataHash, bytes data);
constructor(PluginMetadata memory metadata) BasePlugin(metadata) {
emit Metadata(metadataHash, metadata.encode());
}
function metadataProvider() public view override returns (uint256 providerType, bytes memory location) {
providerType = uint256(MetadataProviderType.Event);
location = abi.encode(address(this));
}
}