-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathTransferableERC1155.sol
151 lines (118 loc) · 6.11 KB
/
TransferableERC1155.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
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {Module} from "../../../Module.sol";
import {Role} from "../../../Role.sol";
import {BeforeBatchTransferCallbackERC1155} from "../../../callback/BeforeBatchTransferCallbackERC1155.sol";
import {BeforeTransferCallbackERC1155} from "../../../callback/BeforeTransferCallbackERC1155.sol";
library TransferableStorage {
/// @custom:storage-location erc7201:token.transferable
bytes32 public constant TRANSFERABLE_STORAGE_POSITION =
keccak256(abi.encode(uint256(keccak256("token.transferable")) - 1)) & ~bytes32(uint256(0xff));
struct Data {
// whether transfers are enabled
bool transferEnabled;
// from/to/operator address => bool, whether transfer is enabled
mapping(address => bool) transferEnabledFor;
}
function data() internal pure returns (Data storage data_) {
bytes32 position = TRANSFERABLE_STORAGE_POSITION;
assembly {
data_.slot := position
}
}
}
contract TransferableERC1155 is Module, BeforeTransferCallbackERC1155, BeforeBatchTransferCallbackERC1155 {
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
/// @notice Emitted on attempt to transfer a token when transfers are disabled.
error TransferDisabled();
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
/// @notice Emitted on attempt to transfer a token when transfers are disabled.
event TransferEnableFor(address indexed target, bool enabled);
/*//////////////////////////////////////////////////////////////
MODULE CONFIG
//////////////////////////////////////////////////////////////*/
/// @notice Returns all implemented callback and module functions.
function getModuleConfig() external pure override returns (ModuleConfig memory config) {
config.callbackFunctions = new CallbackFunction[](2);
config.fallbackFunctions = new FallbackFunction[](4);
config.callbackFunctions[0] = CallbackFunction(this.beforeTransferERC1155.selector);
config.callbackFunctions[1] = CallbackFunction(this.beforeBatchTransferERC1155.selector);
config.fallbackFunctions[0] = FallbackFunction({selector: this.isTransferEnabled.selector, permissionBits: 0});
config.fallbackFunctions[1] =
FallbackFunction({selector: this.isTransferEnabledFor.selector, permissionBits: 0});
config.fallbackFunctions[2] =
FallbackFunction({selector: this.setTransferable.selector, permissionBits: Role._MANAGER_ROLE});
config.fallbackFunctions[3] =
FallbackFunction({selector: this.setTransferableFor.selector, permissionBits: Role._MANAGER_ROLE});
config.requiredInterfaces = new bytes4[](1);
config.requiredInterfaces[0] = 0xd9b67a26; // ERC1155
config.registerInstallationCallback = true;
}
/// @dev Called by a Core into an Module during the installation of the Module.
function onInstall(bytes calldata data) external {
_transferableStorage().transferEnabled = true;
}
/// @dev Called by a Core into an Module during the uninstallation of the Module.
function onUninstall(bytes calldata data) external {}
/*//////////////////////////////////////////////////////////////
CALLBACK FUNCTIONS
//////////////////////////////////////////////////////////////*/
/// @notice Callback function for ERC1155.safeTransferFrom
function beforeTransferERC1155(address from, address to, uint256, uint256)
external
virtual
override
returns (bytes memory)
{
TransferableStorage.Data storage data = _transferableStorage();
bool isOperatorAllowed =
data.transferEnabledFor[msg.sender] || data.transferEnabledFor[from] || data.transferEnabledFor[to];
if (!isOperatorAllowed && !data.transferEnabled) {
revert TransferDisabled();
}
}
/// @notice Callback function for ERC1155.safeBatchTransferFrom
function beforeBatchTransferERC1155(address from, address to, uint256[] calldata, uint256[] calldata)
external
virtual
override
returns (bytes memory)
{
TransferableStorage.Data storage data = _transferableStorage();
bool isOperatorAllowed =
data.transferEnabledFor[msg.sender] || data.transferEnabledFor[from] || data.transferEnabledFor[to];
if (!isOperatorAllowed && !data.transferEnabled) {
revert TransferDisabled();
}
}
/*//////////////////////////////////////////////////////////////
FALLBACK FUNCTIONS
//////////////////////////////////////////////////////////////*/
/// @notice Returns whether transfers is enabled for the token.
function isTransferEnabled() external view returns (bool) {
return _transferableStorage().transferEnabled;
}
/// @notice Returns whether transfers is enabled for the target for the token.
function isTransferEnabledFor(address target) external view returns (bool) {
return _transferableStorage().transferEnabledFor[target];
}
/// @notice Set transferability for a token.
function setTransferable(bool enableTransfer) external {
_transferableStorage().transferEnabled = enableTransfer;
}
/// @notice Set transferability for an operator for a token.
function setTransferableFor(address target, bool enableTransfer) external {
_transferableStorage().transferEnabledFor[target] = enableTransfer;
emit TransferEnableFor(target, enableTransfer);
}
/*//////////////////////////////////////////////////////////////
INTERNAL FUNCTIONS
//////////////////////////////////////////////////////////////*/
function _transferableStorage() internal pure returns (TransferableStorage.Data storage) {
return TransferableStorage.data();
}
}