-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Allowlist sample plugin, refactor test base
- Loading branch information
Showing
11 changed files
with
679 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.25; | ||
|
||
import {PackedUserOperation} from "@eth-infinitism/account-abstraction/interfaces/PackedUserOperation.sol"; | ||
|
||
import {PluginMetadata, PluginManifest} from "../../interfaces/IPlugin.sol"; | ||
import {IValidationHook} from "../../interfaces/IValidationHook.sol"; | ||
import {IStandardExecutor, Call} from "../../interfaces/IStandardExecutor.sol"; | ||
import {BasePlugin} from "../../plugins/BasePlugin.sol"; | ||
|
||
contract AllowlistPlugin is IValidationHook, BasePlugin { | ||
enum FunctionId { | ||
PRE_VALIDATION_HOOK | ||
} | ||
|
||
struct AllowlistInit { | ||
address target; | ||
bool hasSelectorAllowlist; | ||
bytes4[] selectors; | ||
} | ||
|
||
struct AllowlistEntry { | ||
bool allowed; | ||
bool hasSelectorAllowlist; | ||
} | ||
|
||
mapping(address target => mapping(address account => AllowlistEntry)) public targetAllowlist; | ||
mapping(address target => mapping(bytes4 selector => mapping(address account => bool))) public | ||
selectorAllowlist; | ||
|
||
error TargetNotAllowed(); | ||
error SelectorNotAllowed(); | ||
error NoSelectorSpecified(); | ||
|
||
function onInstall(bytes calldata data) external override { | ||
AllowlistInit[] memory init = abi.decode(data, (AllowlistInit[])); | ||
|
||
for (uint256 i = 0; i < init.length; i++) { | ||
targetAllowlist[init[i].target][msg.sender] = AllowlistEntry(true, init[i].hasSelectorAllowlist); | ||
|
||
if (init[i].hasSelectorAllowlist) { | ||
for (uint256 j = 0; j < init[i].selectors.length; j++) { | ||
selectorAllowlist[init[i].target][init[i].selectors[j]][msg.sender] = true; | ||
} | ||
} | ||
} | ||
} | ||
|
||
function onUninstall(bytes calldata data) external override { | ||
AllowlistInit[] memory init = abi.decode(data, (AllowlistInit[])); | ||
|
||
for (uint256 i = 0; i < init.length; i++) { | ||
delete targetAllowlist[init[i].target][msg.sender]; | ||
|
||
if (init[i].hasSelectorAllowlist) { | ||
for (uint256 j = 0; j < init[i].selectors.length; j++) { | ||
delete selectorAllowlist[init[i].target][init[i].selectors[j]][msg.sender]; | ||
} | ||
} | ||
} | ||
} | ||
|
||
function setAllowlistTarget(address target, bool allowed, bool hasSelectorAllowlist) external { | ||
targetAllowlist[target][msg.sender] = AllowlistEntry(allowed, hasSelectorAllowlist); | ||
} | ||
|
||
function setAllowlistSelector(address target, bytes4 selector, bool allowed) external { | ||
selectorAllowlist[target][selector][msg.sender] = allowed; | ||
} | ||
|
||
function preUserOpValidationHook(uint8 functionId, PackedUserOperation calldata userOp, bytes32) | ||
external | ||
view | ||
override | ||
returns (uint256) | ||
{ | ||
if (functionId == uint8(FunctionId.PRE_VALIDATION_HOOK)) { | ||
_checkAllowlistCalldata(userOp.callData); | ||
return 0; | ||
} | ||
revert NotImplemented(); | ||
} | ||
|
||
function preRuntimeValidationHook(uint8 functionId, address, uint256, bytes calldata data, bytes calldata) | ||
external | ||
view | ||
override | ||
{ | ||
if (functionId == uint8(FunctionId.PRE_VALIDATION_HOOK)) { | ||
_checkAllowlistCalldata(data); | ||
return; | ||
} | ||
|
||
revert NotImplemented(); | ||
} | ||
|
||
function pluginMetadata() external pure override returns (PluginMetadata memory) { | ||
PluginMetadata memory metadata; | ||
metadata.name = "Allowlist Plugin"; | ||
metadata.version = "v0.0.1"; | ||
metadata.author = "ERC-6900 Working Group"; | ||
|
||
return metadata; | ||
} | ||
|
||
// solhint-disable-next-line no-empty-blocks | ||
function pluginManifest() external pure override returns (PluginManifest memory) {} | ||
|
||
function _checkAllowlistCalldata(bytes calldata callData) internal view { | ||
if (bytes4(callData[:4]) == IStandardExecutor.execute.selector) { | ||
(address target,, bytes memory data) = abi.decode(callData[4:], (address, uint256, bytes)); | ||
_checkCallPermission(msg.sender, target, data); | ||
} else if (bytes4(callData[:4]) == IStandardExecutor.executeBatch.selector) { | ||
Call[] memory calls = abi.decode(callData[4:], (Call[])); | ||
|
||
for (uint256 i = 0; i < calls.length; i++) { | ||
_checkCallPermission(msg.sender, calls[i].target, calls[i].data); | ||
} | ||
} | ||
} | ||
|
||
function _checkCallPermission(address account, address target, bytes memory data) internal view { | ||
AllowlistEntry storage entry = targetAllowlist[target][account]; | ||
(bool allowed, bool hasSelectorAllowlist) = (entry.allowed, entry.hasSelectorAllowlist); | ||
|
||
if (!allowed) { | ||
revert TargetNotAllowed(); | ||
} | ||
|
||
if (hasSelectorAllowlist) { | ||
if (data.length < 4) { | ||
revert NoSelectorSpecified(); | ||
} | ||
|
||
bytes4 selector = bytes4(data); | ||
|
||
if (!selectorAllowlist[target][selector][account]) { | ||
revert SelectorNotAllowed(); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.