@artblocks/contracts 1.2.1 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/artifacts/contracts/BytecodeStorageReaders/BytecodeStorageReaderContractV2_Web3Call.sol/BytecodeStorageReaderContractV2_Web3Call.json +201 -0
- package/artifacts/contracts/BytecodeStorageReaders/UniversalBytecodeStorageReader.sol/UniversalBytecodeStorageReader.json +2 -2
- package/artifacts/contracts/DependencyRegistryV0.sol/DependencyRegistryV0.json +42 -53
- package/artifacts/contracts/engine/V3/GenArt721CoreV3_Engine_Flex.sol/GenArt721CoreV3_Engine_Flex.json +2 -2
- package/artifacts/contracts/generator/GenArt721GeneratorV0.sol/GenArt721GeneratorV0.json +2 -2
- package/artifacts/contracts/interfaces/v0.8.x/IDelegateRegistry.sol/IDelegateRegistry.json +820 -0
- package/artifacts/contracts/interfaces/v0.8.x/IDependencyRegistryV0.sol/IDependencyRegistryV0.json +13 -0
- package/artifacts/contracts/interfaces/v0.8.x/IPMPAugmentHook.sol/IPMPAugmentHook.json +83 -0
- package/artifacts/contracts/interfaces/v0.8.x/IPMPConfigureHook.sol/IPMPConfigureHook.json +80 -0
- package/artifacts/contracts/interfaces/v0.8.x/IPMPV0.sol/IPMPV0.json +402 -0
- package/artifacts/contracts/interfaces/v0.8.x/IUniversalBytecodeStorageReader.sol/IUniversalBytecodeStorageReader.json +13 -0
- package/artifacts/contracts/interfaces/v0.8.x/IWeb3Call.sol/IWeb3Call.json +47 -0
- package/artifacts/contracts/libs/integration-refs/delegation-registry/DelegateRegistry.sol/DelegateRegistry.json +846 -0
- package/artifacts/contracts/libs/integration-refs/delegation-registry/libraries/RegistryHashes.sol/RegistryHashes.json +10 -0
- package/artifacts/contracts/libs/integration-refs/delegation-registry/libraries/RegistryOps.sol/RegistryOps.json +10 -0
- package/artifacts/contracts/libs/integration-refs/delegation-registry/libraries/RegistryStorage.sol/RegistryStorage.json +10 -0
- package/artifacts/contracts/libs/v0.8.x/DependencyRegistryStorageLib.sol/DependencyRegistryStorageLib.json +2 -2
- package/artifacts/contracts/libs/v0.8.x/ImmutableStringArray.sol/ImmutableStringArray.json +10 -0
- package/artifacts/contracts/libs/v0.8.x/V3FlexLib.sol/V3FlexLib.json +2 -2
- package/artifacts/contracts/mock/ImmutableStringArrayMock.sol/ImmutableStringArrayMock.json +69 -0
- package/artifacts/contracts/mock/MockPMPAugmentHook.sol/MockPMPAugmentHook.json +214 -0
- package/artifacts/contracts/mock/MockPMPConfigureHook.sol/MockPMPConfigureHook.json +236 -0
- package/artifacts/contracts/web3call/PMPV0.sol/PMPV0.json +629 -0
- package/artifacts/contracts/web3call/Web3Call.sol/Web3Call.json +66 -0
- package/artifacts/contracts/web3call/augment-hooks/AbstractPMPAugmentHook.sol/AbstractPMPAugmentHook.json +83 -0
- package/artifacts/contracts/web3call/augment-hooks/InjectBaseGasFee.sol/InjectBaseGasFee.json +83 -0
- package/artifacts/contracts/web3call/augment-hooks/InjectChromieSquiggleFloorPrice.sol/IUniswapV2Pair.json +60 -0
- package/artifacts/contracts/web3call/augment-hooks/InjectChromieSquiggleFloorPrice.sol/InjectChromieSquiggleFloorPrice.json +107 -0
- package/artifacts/contracts/web3call/augment-hooks/InjectIsNounsDaoMember.sol/InjectIsNounsDaoMember.json +96 -0
- package/artifacts/contracts/web3call/augment-hooks/InjectIsProjectFullyMinted.sol/InjectIsProjectFullyMinted.json +83 -0
- package/artifacts/contracts/web3call/augment-hooks/InjectPolyptychTokenHash.sol/InjectPolyptychTokenHash.json +141 -0
- package/artifacts/contracts/web3call/augment-hooks/InjectTokenHashSeed.sol/InjectTokenHashSeed.json +99 -0
- package/artifacts/contracts/web3call/augment-hooks/InjectTokenOwner.sol/InjectTokenOwner.json +99 -0
- package/artifacts/contracts/web3call/augment-hooks/InjectTokenOwnerEthBalance.sol/InjectTokenOwnerEthBalance.json +83 -0
- package/artifacts/contracts/web3call/augment-hooks/InjectUSDCTotalSupply.sol/InjectUSDCTotalSupply.json +107 -0
- package/artifacts/contracts/web3call/configure-hooks/abstractPMPConfigureHook.sol/AbstractPMPConfigureHook.json +80 -0
- package/contracts/BytecodeStorageReaders/BytecodeStorageReaderContractV2_Web3Call.sol +128 -0
- package/contracts/DependencyRegistryV0.sol +67 -28
- package/contracts/engine/V3/GenArt721CoreV3_Engine_Flex.sol +7 -1
- package/contracts/generator/GenArt721GeneratorV0.sol +77 -8
- package/contracts/interfaces/v0.8.x/IDelegateRegistry.sol +318 -0
- package/contracts/interfaces/v0.8.x/IDependencyRegistryV0.sol +2 -0
- package/contracts/interfaces/v0.8.x/IPMPAugmentHook.sol +31 -0
- package/contracts/interfaces/v0.8.x/IPMPConfigureHook.sol +25 -0
- package/contracts/interfaces/v0.8.x/IPMPV0.sol +224 -0
- package/contracts/interfaces/v0.8.x/IUniversalBytecodeStorageReader.sol +5 -0
- package/contracts/interfaces/v0.8.x/IWeb3Call.sol +28 -0
- package/contracts/libs/integration-refs/delegation-registry/DelegateRegistry.sol +753 -0
- package/contracts/libs/integration-refs/delegation-registry/libraries/RegistryHashes.sol +359 -0
- package/contracts/libs/integration-refs/delegation-registry/libraries/RegistryOps.sol +31 -0
- package/contracts/libs/integration-refs/delegation-registry/libraries/RegistryStorage.sol +87 -0
- package/contracts/libs/v0.8.x/DependencyRegistryStorageLib.sol +3 -0
- package/contracts/libs/v0.8.x/ImmutableStringArray.sol +301 -0
- package/contracts/libs/v0.8.x/V3FlexLib.sol +7 -1
- package/contracts/mock/ImmutableStringArrayMock.sol +47 -0
- package/contracts/mock/MockPMPAugmentHook.sol +170 -0
- package/contracts/mock/MockPMPConfigureHook.sol +78 -0
- package/contracts/web3call/PMPV0.sol +1126 -0
- package/contracts/web3call/Web3Call.sol +25 -0
- package/contracts/web3call/augment-hooks/AbstractPMPAugmentHook.sol +46 -0
- package/contracts/web3call/augment-hooks/InjectBaseGasFee.sol +57 -0
- package/contracts/web3call/augment-hooks/InjectChromieSquiggleFloorPrice.sol +103 -0
- package/contracts/web3call/augment-hooks/InjectIsNounsDaoMember.sol +66 -0
- package/contracts/web3call/augment-hooks/InjectIsProjectFullyMinted.sol +73 -0
- package/contracts/web3call/augment-hooks/InjectPolyptychTokenHash.sol +88 -0
- package/contracts/web3call/augment-hooks/InjectTokenHashSeed.sol +62 -0
- package/contracts/web3call/augment-hooks/InjectTokenOwner.sol +60 -0
- package/contracts/web3call/augment-hooks/InjectTokenOwnerEthBalance.sol +61 -0
- package/contracts/web3call/augment-hooks/InjectUSDCTotalSupply.sol +69 -0
- package/contracts/web3call/configure-hooks/abstractPMPConfigureHook.sol +41 -0
- package/package.json +5 -5
|
@@ -0,0 +1,753 @@
|
|
|
1
|
+
// SPDX-License-Identifier: CC0-1.0
|
|
2
|
+
pragma solidity ^0.8.21;
|
|
3
|
+
|
|
4
|
+
import {IDelegateRegistry as IDelegateRegistry} from "../../../interfaces/v0.8.x/IDelegateRegistry.sol";
|
|
5
|
+
import {RegistryHashes as Hashes} from "./libraries/RegistryHashes.sol";
|
|
6
|
+
import {RegistryStorage as Storage} from "./libraries/RegistryStorage.sol";
|
|
7
|
+
import {RegistryOps as Ops} from "./libraries/RegistryOps.sol";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @title DelegateRegistry
|
|
11
|
+
* @custom:version 2.0
|
|
12
|
+
* @custom:coauthor foobar (0xfoobar)
|
|
13
|
+
* @custom:coauthor mireynolds
|
|
14
|
+
* @notice A standalone immutable registry storing delegated permissions from one address to another
|
|
15
|
+
*/
|
|
16
|
+
contract DelegateRegistry is IDelegateRegistry {
|
|
17
|
+
/// @dev Only this mapping should be used to verify delegations; the other mapping arrays are for enumerations
|
|
18
|
+
mapping(bytes32 delegationHash => bytes32[5] delegationStorage)
|
|
19
|
+
internal delegations;
|
|
20
|
+
|
|
21
|
+
/// @dev Vault delegation enumeration outbox, for pushing new hashes only
|
|
22
|
+
mapping(address from => bytes32[] delegationHashes)
|
|
23
|
+
internal outgoingDelegationHashes;
|
|
24
|
+
|
|
25
|
+
/// @dev Delegate enumeration inbox, for pushing new hashes only
|
|
26
|
+
mapping(address to => bytes32[] delegationHashes)
|
|
27
|
+
internal incomingDelegationHashes;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* ----------- WRITE -----------
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/// @inheritdoc IDelegateRegistry
|
|
34
|
+
function multicall(
|
|
35
|
+
bytes[] calldata data
|
|
36
|
+
) external payable override returns (bytes[] memory results) {
|
|
37
|
+
results = new bytes[](data.length);
|
|
38
|
+
bool success;
|
|
39
|
+
unchecked {
|
|
40
|
+
for (uint256 i = 0; i < data.length; ++i) {
|
|
41
|
+
//slither-disable-next-line calls-loop,delegatecall-loop
|
|
42
|
+
(success, results[i]) = address(this).delegatecall(data[i]);
|
|
43
|
+
if (!success) revert MulticallFailed();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/// @inheritdoc IDelegateRegistry
|
|
49
|
+
function delegateAll(
|
|
50
|
+
address to,
|
|
51
|
+
bytes32 rights,
|
|
52
|
+
bool enable
|
|
53
|
+
) external payable override returns (bytes32 hash) {
|
|
54
|
+
hash = Hashes.allHash(msg.sender, rights, to);
|
|
55
|
+
bytes32 location = Hashes.location(hash);
|
|
56
|
+
address loadedFrom = _loadFrom(location);
|
|
57
|
+
if (enable) {
|
|
58
|
+
if (loadedFrom == Storage.DELEGATION_EMPTY) {
|
|
59
|
+
_pushDelegationHashes(msg.sender, to, hash);
|
|
60
|
+
_writeDelegationAddresses(location, msg.sender, to, address(0));
|
|
61
|
+
if (rights != "")
|
|
62
|
+
_writeDelegation(
|
|
63
|
+
location,
|
|
64
|
+
Storage.POSITIONS_RIGHTS,
|
|
65
|
+
rights
|
|
66
|
+
);
|
|
67
|
+
} else if (loadedFrom == Storage.DELEGATION_REVOKED) {
|
|
68
|
+
_updateFrom(location, msg.sender);
|
|
69
|
+
}
|
|
70
|
+
} else if (loadedFrom == msg.sender) {
|
|
71
|
+
_updateFrom(location, Storage.DELEGATION_REVOKED);
|
|
72
|
+
}
|
|
73
|
+
emit DelegateAll(msg.sender, to, rights, enable);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/// @inheritdoc IDelegateRegistry
|
|
77
|
+
function delegateContract(
|
|
78
|
+
address to,
|
|
79
|
+
address contract_,
|
|
80
|
+
bytes32 rights,
|
|
81
|
+
bool enable
|
|
82
|
+
) external payable override returns (bytes32 hash) {
|
|
83
|
+
hash = Hashes.contractHash(msg.sender, rights, to, contract_);
|
|
84
|
+
bytes32 location = Hashes.location(hash);
|
|
85
|
+
address loadedFrom = _loadFrom(location);
|
|
86
|
+
if (enable) {
|
|
87
|
+
if (loadedFrom == Storage.DELEGATION_EMPTY) {
|
|
88
|
+
_pushDelegationHashes(msg.sender, to, hash);
|
|
89
|
+
_writeDelegationAddresses(location, msg.sender, to, contract_);
|
|
90
|
+
if (rights != "")
|
|
91
|
+
_writeDelegation(
|
|
92
|
+
location,
|
|
93
|
+
Storage.POSITIONS_RIGHTS,
|
|
94
|
+
rights
|
|
95
|
+
);
|
|
96
|
+
} else if (loadedFrom == Storage.DELEGATION_REVOKED) {
|
|
97
|
+
_updateFrom(location, msg.sender);
|
|
98
|
+
}
|
|
99
|
+
} else if (loadedFrom == msg.sender) {
|
|
100
|
+
_updateFrom(location, Storage.DELEGATION_REVOKED);
|
|
101
|
+
}
|
|
102
|
+
emit DelegateContract(msg.sender, to, contract_, rights, enable);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/// @inheritdoc IDelegateRegistry
|
|
106
|
+
function delegateERC721(
|
|
107
|
+
address to,
|
|
108
|
+
address contract_,
|
|
109
|
+
uint256 tokenId,
|
|
110
|
+
bytes32 rights,
|
|
111
|
+
bool enable
|
|
112
|
+
) external payable override returns (bytes32 hash) {
|
|
113
|
+
hash = Hashes.erc721Hash(msg.sender, rights, to, tokenId, contract_);
|
|
114
|
+
bytes32 location = Hashes.location(hash);
|
|
115
|
+
address loadedFrom = _loadFrom(location);
|
|
116
|
+
if (enable) {
|
|
117
|
+
if (loadedFrom == Storage.DELEGATION_EMPTY) {
|
|
118
|
+
_pushDelegationHashes(msg.sender, to, hash);
|
|
119
|
+
_writeDelegationAddresses(location, msg.sender, to, contract_);
|
|
120
|
+
_writeDelegation(location, Storage.POSITIONS_TOKEN_ID, tokenId);
|
|
121
|
+
if (rights != "")
|
|
122
|
+
_writeDelegation(
|
|
123
|
+
location,
|
|
124
|
+
Storage.POSITIONS_RIGHTS,
|
|
125
|
+
rights
|
|
126
|
+
);
|
|
127
|
+
} else if (loadedFrom == Storage.DELEGATION_REVOKED) {
|
|
128
|
+
_updateFrom(location, msg.sender);
|
|
129
|
+
}
|
|
130
|
+
} else if (loadedFrom == msg.sender) {
|
|
131
|
+
_updateFrom(location, Storage.DELEGATION_REVOKED);
|
|
132
|
+
}
|
|
133
|
+
emit DelegateERC721(msg.sender, to, contract_, tokenId, rights, enable);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// @inheritdoc IDelegateRegistry
|
|
137
|
+
function delegateERC20(
|
|
138
|
+
address to,
|
|
139
|
+
address contract_,
|
|
140
|
+
bytes32 rights,
|
|
141
|
+
uint256 amount
|
|
142
|
+
) external payable override returns (bytes32 hash) {
|
|
143
|
+
hash = Hashes.erc20Hash(msg.sender, rights, to, contract_);
|
|
144
|
+
bytes32 location = Hashes.location(hash);
|
|
145
|
+
address loadedFrom = _loadFrom(location);
|
|
146
|
+
if (amount != 0) {
|
|
147
|
+
if (loadedFrom == Storage.DELEGATION_EMPTY) {
|
|
148
|
+
_pushDelegationHashes(msg.sender, to, hash);
|
|
149
|
+
_writeDelegationAddresses(location, msg.sender, to, contract_);
|
|
150
|
+
_writeDelegation(location, Storage.POSITIONS_AMOUNT, amount);
|
|
151
|
+
if (rights != "")
|
|
152
|
+
_writeDelegation(
|
|
153
|
+
location,
|
|
154
|
+
Storage.POSITIONS_RIGHTS,
|
|
155
|
+
rights
|
|
156
|
+
);
|
|
157
|
+
} else if (loadedFrom == Storage.DELEGATION_REVOKED) {
|
|
158
|
+
_updateFrom(location, msg.sender);
|
|
159
|
+
_writeDelegation(location, Storage.POSITIONS_AMOUNT, amount);
|
|
160
|
+
} else if (loadedFrom == msg.sender) {
|
|
161
|
+
_writeDelegation(location, Storage.POSITIONS_AMOUNT, amount);
|
|
162
|
+
}
|
|
163
|
+
} else if (loadedFrom == msg.sender) {
|
|
164
|
+
_updateFrom(location, Storage.DELEGATION_REVOKED);
|
|
165
|
+
_writeDelegation(location, Storage.POSITIONS_AMOUNT, uint256(0));
|
|
166
|
+
}
|
|
167
|
+
emit DelegateERC20(msg.sender, to, contract_, rights, amount);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/// @inheritdoc IDelegateRegistry
|
|
171
|
+
function delegateERC1155(
|
|
172
|
+
address to,
|
|
173
|
+
address contract_,
|
|
174
|
+
uint256 tokenId,
|
|
175
|
+
bytes32 rights,
|
|
176
|
+
uint256 amount
|
|
177
|
+
) external payable override returns (bytes32 hash) {
|
|
178
|
+
hash = Hashes.erc1155Hash(msg.sender, rights, to, tokenId, contract_);
|
|
179
|
+
bytes32 location = Hashes.location(hash);
|
|
180
|
+
address loadedFrom = _loadFrom(location);
|
|
181
|
+
if (amount != 0) {
|
|
182
|
+
if (loadedFrom == Storage.DELEGATION_EMPTY) {
|
|
183
|
+
_pushDelegationHashes(msg.sender, to, hash);
|
|
184
|
+
_writeDelegationAddresses(location, msg.sender, to, contract_);
|
|
185
|
+
_writeDelegation(location, Storage.POSITIONS_TOKEN_ID, tokenId);
|
|
186
|
+
_writeDelegation(location, Storage.POSITIONS_AMOUNT, amount);
|
|
187
|
+
if (rights != "")
|
|
188
|
+
_writeDelegation(
|
|
189
|
+
location,
|
|
190
|
+
Storage.POSITIONS_RIGHTS,
|
|
191
|
+
rights
|
|
192
|
+
);
|
|
193
|
+
} else if (loadedFrom == Storage.DELEGATION_REVOKED) {
|
|
194
|
+
_updateFrom(location, msg.sender);
|
|
195
|
+
_writeDelegation(location, Storage.POSITIONS_AMOUNT, amount);
|
|
196
|
+
} else if (loadedFrom == msg.sender) {
|
|
197
|
+
_writeDelegation(location, Storage.POSITIONS_AMOUNT, amount);
|
|
198
|
+
}
|
|
199
|
+
} else if (loadedFrom == msg.sender) {
|
|
200
|
+
_updateFrom(location, Storage.DELEGATION_REVOKED);
|
|
201
|
+
_writeDelegation(location, Storage.POSITIONS_AMOUNT, uint256(0));
|
|
202
|
+
}
|
|
203
|
+
emit DelegateERC1155(
|
|
204
|
+
msg.sender,
|
|
205
|
+
to,
|
|
206
|
+
contract_,
|
|
207
|
+
tokenId,
|
|
208
|
+
rights,
|
|
209
|
+
amount
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/// @dev Transfer native token out
|
|
214
|
+
function sweep() external {
|
|
215
|
+
assembly ("memory-safe") {
|
|
216
|
+
// This hardcoded address is a CREATE2 factory counterfactual smart contract wallet that will always accept native token transfers
|
|
217
|
+
let result := call(
|
|
218
|
+
gas(),
|
|
219
|
+
0x000000dE1E80ea5a234FB5488fee2584251BC7e8,
|
|
220
|
+
selfbalance(),
|
|
221
|
+
0,
|
|
222
|
+
0,
|
|
223
|
+
0,
|
|
224
|
+
0
|
|
225
|
+
)
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* ----------- CHECKS -----------
|
|
231
|
+
*/
|
|
232
|
+
|
|
233
|
+
/// @inheritdoc IDelegateRegistry
|
|
234
|
+
function checkDelegateForAll(
|
|
235
|
+
address to,
|
|
236
|
+
address from,
|
|
237
|
+
bytes32 rights
|
|
238
|
+
) external view override returns (bool valid) {
|
|
239
|
+
if (!_invalidFrom(from)) {
|
|
240
|
+
valid = _validateFrom(Hashes.allLocation(from, "", to), from);
|
|
241
|
+
if (!Ops.or(rights == "", valid))
|
|
242
|
+
valid = _validateFrom(
|
|
243
|
+
Hashes.allLocation(from, rights, to),
|
|
244
|
+
from
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
assembly ("memory-safe") {
|
|
248
|
+
// Only first 32 bytes of scratch space is accessed
|
|
249
|
+
mstore(0, iszero(iszero(valid))) // Compiler cleans dirty booleans on the stack to 1, so do the same here
|
|
250
|
+
return(0, 32) // Direct return, skips Solidity's redundant copying to save gas
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/// @inheritdoc IDelegateRegistry
|
|
255
|
+
function checkDelegateForContract(
|
|
256
|
+
address to,
|
|
257
|
+
address from,
|
|
258
|
+
address contract_,
|
|
259
|
+
bytes32 rights
|
|
260
|
+
) external view override returns (bool valid) {
|
|
261
|
+
if (!_invalidFrom(from)) {
|
|
262
|
+
valid =
|
|
263
|
+
_validateFrom(Hashes.allLocation(from, "", to), from) ||
|
|
264
|
+
_validateFrom(
|
|
265
|
+
Hashes.contractLocation(from, "", to, contract_),
|
|
266
|
+
from
|
|
267
|
+
);
|
|
268
|
+
if (!Ops.or(rights == "", valid)) {
|
|
269
|
+
valid =
|
|
270
|
+
_validateFrom(Hashes.allLocation(from, rights, to), from) ||
|
|
271
|
+
_validateFrom(
|
|
272
|
+
Hashes.contractLocation(from, rights, to, contract_),
|
|
273
|
+
from
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
assembly ("memory-safe") {
|
|
278
|
+
// Only first 32 bytes of scratch space is accessed
|
|
279
|
+
mstore(0, iszero(iszero(valid))) // Compiler cleans dirty booleans on the stack to 1, so do the same here
|
|
280
|
+
return(0, 32) // Direct return, skips Solidity's redundant copying to save gas
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/// @inheritdoc IDelegateRegistry
|
|
285
|
+
function checkDelegateForERC721(
|
|
286
|
+
address to,
|
|
287
|
+
address from,
|
|
288
|
+
address contract_,
|
|
289
|
+
uint256 tokenId,
|
|
290
|
+
bytes32 rights
|
|
291
|
+
) external view override returns (bool valid) {
|
|
292
|
+
if (!_invalidFrom(from)) {
|
|
293
|
+
valid =
|
|
294
|
+
_validateFrom(Hashes.allLocation(from, "", to), from) ||
|
|
295
|
+
_validateFrom(
|
|
296
|
+
Hashes.contractLocation(from, "", to, contract_),
|
|
297
|
+
from
|
|
298
|
+
) ||
|
|
299
|
+
_validateFrom(
|
|
300
|
+
Hashes.erc721Location(from, "", to, tokenId, contract_),
|
|
301
|
+
from
|
|
302
|
+
);
|
|
303
|
+
if (!Ops.or(rights == "", valid)) {
|
|
304
|
+
valid =
|
|
305
|
+
_validateFrom(Hashes.allLocation(from, rights, to), from) ||
|
|
306
|
+
_validateFrom(
|
|
307
|
+
Hashes.contractLocation(from, rights, to, contract_),
|
|
308
|
+
from
|
|
309
|
+
) ||
|
|
310
|
+
_validateFrom(
|
|
311
|
+
Hashes.erc721Location(
|
|
312
|
+
from,
|
|
313
|
+
rights,
|
|
314
|
+
to,
|
|
315
|
+
tokenId,
|
|
316
|
+
contract_
|
|
317
|
+
),
|
|
318
|
+
from
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
assembly ("memory-safe") {
|
|
323
|
+
// Only first 32 bytes of scratch space is accessed
|
|
324
|
+
mstore(0, iszero(iszero(valid))) // Compiler cleans dirty booleans on the stack to 1, so do the same here
|
|
325
|
+
return(0, 32) // Direct return, skips Solidity's redundant copying to save gas
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/// @inheritdoc IDelegateRegistry
|
|
330
|
+
function checkDelegateForERC20(
|
|
331
|
+
address to,
|
|
332
|
+
address from,
|
|
333
|
+
address contract_,
|
|
334
|
+
bytes32 rights
|
|
335
|
+
) external view override returns (uint256 amount) {
|
|
336
|
+
if (!_invalidFrom(from)) {
|
|
337
|
+
amount = (_validateFrom(Hashes.allLocation(from, "", to), from) ||
|
|
338
|
+
_validateFrom(
|
|
339
|
+
Hashes.contractLocation(from, "", to, contract_),
|
|
340
|
+
from
|
|
341
|
+
))
|
|
342
|
+
? type(uint256).max
|
|
343
|
+
: _loadDelegationUint(
|
|
344
|
+
Hashes.erc20Location(from, "", to, contract_),
|
|
345
|
+
Storage.POSITIONS_AMOUNT
|
|
346
|
+
);
|
|
347
|
+
if (!Ops.or(rights == "", amount == type(uint256).max)) {
|
|
348
|
+
uint256 rightsBalance = (_validateFrom(
|
|
349
|
+
Hashes.allLocation(from, rights, to),
|
|
350
|
+
from
|
|
351
|
+
) ||
|
|
352
|
+
_validateFrom(
|
|
353
|
+
Hashes.contractLocation(from, rights, to, contract_),
|
|
354
|
+
from
|
|
355
|
+
))
|
|
356
|
+
? type(uint256).max
|
|
357
|
+
: _loadDelegationUint(
|
|
358
|
+
Hashes.erc20Location(from, rights, to, contract_),
|
|
359
|
+
Storage.POSITIONS_AMOUNT
|
|
360
|
+
);
|
|
361
|
+
amount = Ops.max(rightsBalance, amount);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
assembly ("memory-safe") {
|
|
365
|
+
mstore(0, amount) // Only first 32 bytes of scratch space being accessed
|
|
366
|
+
return(0, 32) // Direct return, skips Solidity's redundant copying to save gas
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/// @inheritdoc IDelegateRegistry
|
|
371
|
+
function checkDelegateForERC1155(
|
|
372
|
+
address to,
|
|
373
|
+
address from,
|
|
374
|
+
address contract_,
|
|
375
|
+
uint256 tokenId,
|
|
376
|
+
bytes32 rights
|
|
377
|
+
) external view override returns (uint256 amount) {
|
|
378
|
+
if (!_invalidFrom(from)) {
|
|
379
|
+
amount = (_validateFrom(Hashes.allLocation(from, "", to), from) ||
|
|
380
|
+
_validateFrom(
|
|
381
|
+
Hashes.contractLocation(from, "", to, contract_),
|
|
382
|
+
from
|
|
383
|
+
))
|
|
384
|
+
? type(uint256).max
|
|
385
|
+
: _loadDelegationUint(
|
|
386
|
+
Hashes.erc1155Location(from, "", to, tokenId, contract_),
|
|
387
|
+
Storage.POSITIONS_AMOUNT
|
|
388
|
+
);
|
|
389
|
+
if (!Ops.or(rights == "", amount == type(uint256).max)) {
|
|
390
|
+
uint256 rightsBalance = (_validateFrom(
|
|
391
|
+
Hashes.allLocation(from, rights, to),
|
|
392
|
+
from
|
|
393
|
+
) ||
|
|
394
|
+
_validateFrom(
|
|
395
|
+
Hashes.contractLocation(from, rights, to, contract_),
|
|
396
|
+
from
|
|
397
|
+
))
|
|
398
|
+
? type(uint256).max
|
|
399
|
+
: _loadDelegationUint(
|
|
400
|
+
Hashes.erc1155Location(
|
|
401
|
+
from,
|
|
402
|
+
rights,
|
|
403
|
+
to,
|
|
404
|
+
tokenId,
|
|
405
|
+
contract_
|
|
406
|
+
),
|
|
407
|
+
Storage.POSITIONS_AMOUNT
|
|
408
|
+
);
|
|
409
|
+
amount = Ops.max(rightsBalance, amount);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
assembly ("memory-safe") {
|
|
413
|
+
mstore(0, amount) // Only first 32 bytes of scratch space is accessed
|
|
414
|
+
return(0, 32) // Direct return, skips Solidity's redundant copying to save gas
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* ----------- ENUMERATIONS -----------
|
|
420
|
+
*/
|
|
421
|
+
|
|
422
|
+
/// @inheritdoc IDelegateRegistry
|
|
423
|
+
function getIncomingDelegations(
|
|
424
|
+
address to
|
|
425
|
+
) external view override returns (Delegation[] memory delegations_) {
|
|
426
|
+
delegations_ = _getValidDelegationsFromHashes(
|
|
427
|
+
incomingDelegationHashes[to]
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/// @inheritdoc IDelegateRegistry
|
|
432
|
+
function getOutgoingDelegations(
|
|
433
|
+
address from
|
|
434
|
+
) external view returns (Delegation[] memory delegations_) {
|
|
435
|
+
delegations_ = _getValidDelegationsFromHashes(
|
|
436
|
+
outgoingDelegationHashes[from]
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/// @inheritdoc IDelegateRegistry
|
|
441
|
+
function getIncomingDelegationHashes(
|
|
442
|
+
address to
|
|
443
|
+
) external view returns (bytes32[] memory delegationHashes) {
|
|
444
|
+
delegationHashes = _getValidDelegationHashesFromHashes(
|
|
445
|
+
incomingDelegationHashes[to]
|
|
446
|
+
);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/// @inheritdoc IDelegateRegistry
|
|
450
|
+
function getOutgoingDelegationHashes(
|
|
451
|
+
address from
|
|
452
|
+
) external view returns (bytes32[] memory delegationHashes) {
|
|
453
|
+
delegationHashes = _getValidDelegationHashesFromHashes(
|
|
454
|
+
outgoingDelegationHashes[from]
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/// @inheritdoc IDelegateRegistry
|
|
459
|
+
function getDelegationsFromHashes(
|
|
460
|
+
bytes32[] calldata hashes
|
|
461
|
+
) external view returns (Delegation[] memory delegations_) {
|
|
462
|
+
delegations_ = new Delegation[](hashes.length);
|
|
463
|
+
unchecked {
|
|
464
|
+
for (uint256 i = 0; i < hashes.length; ++i) {
|
|
465
|
+
bytes32 location = Hashes.location(hashes[i]);
|
|
466
|
+
address from = _loadFrom(location);
|
|
467
|
+
if (_invalidFrom(from)) {
|
|
468
|
+
delegations_[i] = Delegation({
|
|
469
|
+
type_: DelegationType.NONE,
|
|
470
|
+
to: address(0),
|
|
471
|
+
from: address(0),
|
|
472
|
+
rights: "",
|
|
473
|
+
amount: 0,
|
|
474
|
+
contract_: address(0),
|
|
475
|
+
tokenId: 0
|
|
476
|
+
});
|
|
477
|
+
} else {
|
|
478
|
+
(
|
|
479
|
+
,
|
|
480
|
+
address to,
|
|
481
|
+
address contract_
|
|
482
|
+
) = _loadDelegationAddresses(location);
|
|
483
|
+
delegations_[i] = Delegation({
|
|
484
|
+
type_: Hashes.decodeType(hashes[i]),
|
|
485
|
+
to: to,
|
|
486
|
+
from: from,
|
|
487
|
+
rights: _loadDelegationBytes32(
|
|
488
|
+
location,
|
|
489
|
+
Storage.POSITIONS_RIGHTS
|
|
490
|
+
),
|
|
491
|
+
amount: _loadDelegationUint(
|
|
492
|
+
location,
|
|
493
|
+
Storage.POSITIONS_AMOUNT
|
|
494
|
+
),
|
|
495
|
+
contract_: contract_,
|
|
496
|
+
tokenId: _loadDelegationUint(
|
|
497
|
+
location,
|
|
498
|
+
Storage.POSITIONS_TOKEN_ID
|
|
499
|
+
)
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* ----------- EXTERNAL STORAGE ACCESS -----------
|
|
508
|
+
*/
|
|
509
|
+
|
|
510
|
+
function readSlot(
|
|
511
|
+
bytes32 location
|
|
512
|
+
) external view returns (bytes32 contents) {
|
|
513
|
+
assembly {
|
|
514
|
+
contents := sload(location)
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
function readSlots(
|
|
519
|
+
bytes32[] calldata locations
|
|
520
|
+
) external view returns (bytes32[] memory contents) {
|
|
521
|
+
uint256 length = locations.length;
|
|
522
|
+
contents = new bytes32[](length);
|
|
523
|
+
bytes32 tempLocation;
|
|
524
|
+
bytes32 tempValue;
|
|
525
|
+
unchecked {
|
|
526
|
+
for (uint256 i = 0; i < length; ++i) {
|
|
527
|
+
tempLocation = locations[i];
|
|
528
|
+
assembly {
|
|
529
|
+
tempValue := sload(tempLocation)
|
|
530
|
+
}
|
|
531
|
+
contents[i] = tempValue;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* ----------- ERC165 -----------
|
|
538
|
+
*/
|
|
539
|
+
|
|
540
|
+
/// @notice Query if a contract implements an ERC-165 interface
|
|
541
|
+
/// @param interfaceId The interface identifier
|
|
542
|
+
/// @return valid Whether the queried interface is supported
|
|
543
|
+
function supportsInterface(
|
|
544
|
+
bytes4 interfaceId
|
|
545
|
+
) external pure returns (bool) {
|
|
546
|
+
return
|
|
547
|
+
Ops.or(
|
|
548
|
+
interfaceId == type(IDelegateRegistry).interfaceId,
|
|
549
|
+
interfaceId == 0x01ffc9a7
|
|
550
|
+
);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* ----------- INTERNAL -----------
|
|
555
|
+
*/
|
|
556
|
+
|
|
557
|
+
/// @dev Helper function to push new delegation hashes to the incoming and outgoing hashes mappings
|
|
558
|
+
function _pushDelegationHashes(
|
|
559
|
+
address from,
|
|
560
|
+
address to,
|
|
561
|
+
bytes32 delegationHash
|
|
562
|
+
) internal {
|
|
563
|
+
outgoingDelegationHashes[from].push(delegationHash);
|
|
564
|
+
incomingDelegationHashes[to].push(delegationHash);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/// @dev Helper function that writes bytes32 data to delegation data location at array position
|
|
568
|
+
function _writeDelegation(
|
|
569
|
+
bytes32 location,
|
|
570
|
+
uint256 position,
|
|
571
|
+
bytes32 data
|
|
572
|
+
) internal {
|
|
573
|
+
assembly {
|
|
574
|
+
sstore(add(location, position), data)
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/// @dev Helper function that writes uint256 data to delegation data location at array position
|
|
579
|
+
function _writeDelegation(
|
|
580
|
+
bytes32 location,
|
|
581
|
+
uint256 position,
|
|
582
|
+
uint256 data
|
|
583
|
+
) internal {
|
|
584
|
+
assembly {
|
|
585
|
+
sstore(add(location, position), data)
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/// @dev Helper function that writes addresses according to the packing rule for delegation storage
|
|
590
|
+
function _writeDelegationAddresses(
|
|
591
|
+
bytes32 location,
|
|
592
|
+
address from,
|
|
593
|
+
address to,
|
|
594
|
+
address contract_
|
|
595
|
+
) internal {
|
|
596
|
+
(bytes32 firstSlot, bytes32 secondSlot) = Storage.packAddresses(
|
|
597
|
+
from,
|
|
598
|
+
to,
|
|
599
|
+
contract_
|
|
600
|
+
);
|
|
601
|
+
uint256 firstPacked = Storage.POSITIONS_FIRST_PACKED;
|
|
602
|
+
uint256 secondPacked = Storage.POSITIONS_SECOND_PACKED;
|
|
603
|
+
assembly {
|
|
604
|
+
sstore(add(location, firstPacked), firstSlot)
|
|
605
|
+
sstore(add(location, secondPacked), secondSlot)
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/// @dev Helper function that writes `from` while preserving the rest of the storage slot
|
|
610
|
+
function _updateFrom(bytes32 location, address from) internal {
|
|
611
|
+
uint256 firstPacked = Storage.POSITIONS_FIRST_PACKED;
|
|
612
|
+
uint256 cleanAddress = Storage.CLEAN_ADDRESS;
|
|
613
|
+
uint256 cleanUpper12Bytes = type(uint256).max << 160;
|
|
614
|
+
assembly {
|
|
615
|
+
let slot := and(
|
|
616
|
+
sload(add(location, firstPacked)),
|
|
617
|
+
cleanUpper12Bytes
|
|
618
|
+
)
|
|
619
|
+
sstore(
|
|
620
|
+
add(location, firstPacked),
|
|
621
|
+
or(slot, and(from, cleanAddress))
|
|
622
|
+
)
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
/// @dev Helper function that takes an array of delegation hashes and returns an array of Delegation structs with their onchain information
|
|
627
|
+
function _getValidDelegationsFromHashes(
|
|
628
|
+
bytes32[] storage hashes
|
|
629
|
+
) internal view returns (Delegation[] memory delegations_) {
|
|
630
|
+
uint256 count = 0;
|
|
631
|
+
uint256 hashesLength = hashes.length;
|
|
632
|
+
bytes32 hash;
|
|
633
|
+
bytes32[] memory filteredHashes = new bytes32[](hashesLength);
|
|
634
|
+
unchecked {
|
|
635
|
+
for (uint256 i = 0; i < hashesLength; ++i) {
|
|
636
|
+
hash = hashes[i];
|
|
637
|
+
if (_invalidFrom(_loadFrom(Hashes.location(hash)))) continue;
|
|
638
|
+
filteredHashes[count++] = hash;
|
|
639
|
+
}
|
|
640
|
+
delegations_ = new Delegation[](count);
|
|
641
|
+
bytes32 location;
|
|
642
|
+
for (uint256 i = 0; i < count; ++i) {
|
|
643
|
+
hash = filteredHashes[i];
|
|
644
|
+
location = Hashes.location(hash);
|
|
645
|
+
(
|
|
646
|
+
address from,
|
|
647
|
+
address to,
|
|
648
|
+
address contract_
|
|
649
|
+
) = _loadDelegationAddresses(location);
|
|
650
|
+
delegations_[i] = Delegation({
|
|
651
|
+
type_: Hashes.decodeType(hash),
|
|
652
|
+
to: to,
|
|
653
|
+
from: from,
|
|
654
|
+
rights: _loadDelegationBytes32(
|
|
655
|
+
location,
|
|
656
|
+
Storage.POSITIONS_RIGHTS
|
|
657
|
+
),
|
|
658
|
+
amount: _loadDelegationUint(
|
|
659
|
+
location,
|
|
660
|
+
Storage.POSITIONS_AMOUNT
|
|
661
|
+
),
|
|
662
|
+
contract_: contract_,
|
|
663
|
+
tokenId: _loadDelegationUint(
|
|
664
|
+
location,
|
|
665
|
+
Storage.POSITIONS_TOKEN_ID
|
|
666
|
+
)
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
/// @dev Helper function that takes an array of delegation hashes and returns an array of valid delegation hashes
|
|
673
|
+
function _getValidDelegationHashesFromHashes(
|
|
674
|
+
bytes32[] storage hashes
|
|
675
|
+
) internal view returns (bytes32[] memory validHashes) {
|
|
676
|
+
uint256 count = 0;
|
|
677
|
+
uint256 hashesLength = hashes.length;
|
|
678
|
+
bytes32 hash;
|
|
679
|
+
bytes32[] memory filteredHashes = new bytes32[](hashesLength);
|
|
680
|
+
unchecked {
|
|
681
|
+
for (uint256 i = 0; i < hashesLength; ++i) {
|
|
682
|
+
hash = hashes[i];
|
|
683
|
+
if (_invalidFrom(_loadFrom(Hashes.location(hash)))) continue;
|
|
684
|
+
filteredHashes[count++] = hash;
|
|
685
|
+
}
|
|
686
|
+
validHashes = new bytes32[](count);
|
|
687
|
+
for (uint256 i = 0; i < count; ++i) {
|
|
688
|
+
validHashes[i] = filteredHashes[i];
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/// @dev Helper function that loads delegation data from a particular array position and returns as bytes32
|
|
694
|
+
function _loadDelegationBytes32(
|
|
695
|
+
bytes32 location,
|
|
696
|
+
uint256 position
|
|
697
|
+
) internal view returns (bytes32 data) {
|
|
698
|
+
assembly {
|
|
699
|
+
data := sload(add(location, position))
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/// @dev Helper function that loads delegation data from a particular array position and returns as uint256
|
|
704
|
+
function _loadDelegationUint(
|
|
705
|
+
bytes32 location,
|
|
706
|
+
uint256 position
|
|
707
|
+
) internal view returns (uint256 data) {
|
|
708
|
+
assembly {
|
|
709
|
+
data := sload(add(location, position))
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
// @dev Helper function that loads the from address from storage according to the packing rule for delegation storage
|
|
714
|
+
function _loadFrom(bytes32 location) internal view returns (address) {
|
|
715
|
+
bytes32 data;
|
|
716
|
+
uint256 firstPacked = Storage.POSITIONS_FIRST_PACKED;
|
|
717
|
+
assembly {
|
|
718
|
+
data := sload(add(location, firstPacked))
|
|
719
|
+
}
|
|
720
|
+
return Storage.unpackAddress(data);
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
/// @dev Helper function to establish whether a delegation is enabled
|
|
724
|
+
function _validateFrom(
|
|
725
|
+
bytes32 location,
|
|
726
|
+
address from
|
|
727
|
+
) internal view returns (bool) {
|
|
728
|
+
return (from == _loadFrom(location));
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
/// @dev Helper function that loads the address for the delegation according to the packing rule for delegation storage
|
|
732
|
+
function _loadDelegationAddresses(
|
|
733
|
+
bytes32 location
|
|
734
|
+
) internal view returns (address from, address to, address contract_) {
|
|
735
|
+
bytes32 firstSlot;
|
|
736
|
+
bytes32 secondSlot;
|
|
737
|
+
uint256 firstPacked = Storage.POSITIONS_FIRST_PACKED;
|
|
738
|
+
uint256 secondPacked = Storage.POSITIONS_SECOND_PACKED;
|
|
739
|
+
assembly {
|
|
740
|
+
firstSlot := sload(add(location, firstPacked))
|
|
741
|
+
secondSlot := sload(add(location, secondPacked))
|
|
742
|
+
}
|
|
743
|
+
(from, to, contract_) = Storage.unpackAddresses(firstSlot, secondSlot);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
function _invalidFrom(address from) internal pure returns (bool) {
|
|
747
|
+
return
|
|
748
|
+
Ops.or(
|
|
749
|
+
from == Storage.DELEGATION_EMPTY,
|
|
750
|
+
from == Storage.DELEGATION_REVOKED
|
|
751
|
+
);
|
|
752
|
+
}
|
|
753
|
+
}
|