Utility contract for setting/enforcing execution permissions per function
Prerequisites and/or dependencies that this project needs to function properly
This project utilizes Truffle for organization of source code and tests, thus it is recommended to install Truffle globally to your current user account
npm install -g truffle
... Or to your project root directory
cd your_project
npm install truffle
Perhaps as easy as one, 2.0,...
NPM and Truffle are recommended for importing and managing dependencies
cd your_project
npm install @solidity-utilities/execution-permissions
Note, source code will be located within the
node_modules/@solidity-utilities/execution-permissions
directory ofyour_project
root
Solidity contracts may then import code via similar syntax as shown
import {
ExecutionPermissions
} from "@solidity-utilities/execution-permissions/contracts/ExecutionPermissions.sol";
import {
IExecutionPermissions,
BatchPermissionEntry
} from "@solidity-utilities/execution-permissions/contracts/interfaces/IExecutionPermissions.sol";
Note, above paths are not relative (ie. there's no
./
preceding the file path) which causes Truffle to search thenode_modules
subs-directories
Review the Truffle -- Package Management via NPM documentation for more details.
In the future, after beta testers have reported bugs and feature requests, it should be possible to link the deployed
ExecutionPermissions
via Truffle migration similar to the following.
migrations/2_example_usage.js
const refExecutionPermissions = "0x0...0"; const ExampleUsage = artifacts.require("ExampleUsage"); module.exports = (deployer, _network, _accounts) { deployer.deploy(ExampleUsage, refExecutionPermissions); };
How to utilize this repository
Write contract(s) that make use of, and extend, ExecutionPermissions
features.
Example contract that utilizes existing
ExecutionPermissions
contract
// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.4.22 <0.9.0;
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import {
IExecutionPermissions,
BatchPermissionEntry
} from "@solidity-utilities/execution-permissions/contracts/interfaces/IExecutionPermissions.sol";
/// @title Example of how to utilize ExecutionPermissions features
/// @author S0AndS0
contract ExampleUsage is Ownable {
address private _permissionStore;
mapping(address => uint256) public account_score;
// Store referenced to `ExecutionPermissions` contract
constructor(address permissionStore_) Ownable() {
_permissionStore = permissionStore_;
}
// Restrict execution to only permitted callers
modifier onlyPermitted() {
require(
IExecutionPermissions(_permissionStore).isPermitted(
bytes4(msg.data),
msg.sender
),
"ExampleUsage: sender not permitted"
);
_;
}
// Example of restricted function
function setScore(uint256 value) external payable onlyPermitted {
account_score[msg.sender] = value;
}
// Allow only contract owner to modify own registration state
function setRegistered(bool state) external payable virtual onlyOwner {
IExecutionPermissions(_permissionStore).setRegistered(state);
}
// Allow only contract owner to modify permissions
function setBatchPermission(BatchPermissionEntry[] memory entries)
external
payable
virtual
onlyOwner
{
IExecutionPermissions(_permissionStore).setBatchPermission(entries);
}
// Allow only contract owner to modify permissions
function setTargetPermission(
bytes4 target,
address caller,
bool state
) external payable virtual onlyOwner {
IExecutionPermissions(_permissionStore).setTargetPermission(
target,
caller,
state
);
}
}
Tip; review the
ts/test
, andtest/solidity
, sub-directories for extensive usage examples
Anyone may utilize the contract on-chain via the following network addresses
migrations/1000_ExampleUsage.js
(example)
'use strict';
module.exports = (deployer, network, accounts) => {
const ExampleUsage = artifacts.require('ExampleUsage');
const parameters = {
permissionStore: '0x90f94E4Fa212Aafb4d9528c3A064815B3378c8b9',
};
deployer.deploy(ExampleUsage, ...Object.values(parameters));
};
Address:
0x90f94E4Fa212Aafb4d9528c3A064815B3378c8b9
Application Programming Interfaces for Solidity smart contracts
Utility contract for setting/enforcing execution permissions per function
Source
Check execution permissions of target function for given caller
Source
contracts/ExecutionPermissions.sol
--isPermitted(bytes4,address)
contracts/interfaces/IExecutionPermissions.sol
--isPermitted(bytes4,address)
Parameters
target
{bytes4} Function ID to checkcaller
{address} Originalmsg.sender
of targeted function
Throws -> {Error} "ExecutionPermissions: instance not registered"
Check execution permissions of target function for given caller
Source
contracts/ExecutionPermissions.sol
--isPermitted(string,address)
contracts/interfaces/IExecutionPermissions.sol
--isPermitted(string,address)
Parameters
target
{string} Function signature to checkcaller
{address} Originalmsg.sender
of targeted function
Throws -> {Error} "ExecutionPermissions: instance not registered"
Developer note -> Note will cost more gas than
isPermitted(bytes4,address)
due to implicit conversion of function signature
string to ID
Assign multiple permission entries in one transaction
Source
contracts/ExecutionPermissions.sol
--setBatchPermission(BatchPermissionEntry[])
contracts/interfaces/IExecutionPermissions.sol
--setBatchPermission(BatchPermissionEntry[])
Parameters
BatchPermissionEntry
{array} entries List of permissions to assign
Throws -> {Error} "ExecutionPermissions: instance not registered"
Developer note -> Note may cost less gas due to fewer initialization
transaction fees of multiple setTargetPermission(bytes4,address,bool)
calls
Assign single function caller permission state
Source
contracts/ExecutionPermissions.sol
--setTargetPermission(bytes4,address,bool)
contracts/interfaces/IExecutionPermissions.sol
--setTargetPermission(bytes4,address,bool)
Parameters
BatchPermissionEntry
{array} entries List of permissions to assigntarget
{bytes4} Function ID to set caller permissioncaller
{address} Originalmsg.sender
of targeted functionstate
{boolean} Value to assign for function caller interaction
Throws -> {Error} "ExecutionPermissions: instance not registered"
Set registration state for calling contract instance
Source
contracts/ExecutionPermissions.sol
--setRegistered(bool)
contracts/interfaces/IExecutionPermissions.sol
--setRegistered(bool)
Parameters
state
{boolean} Settrue
for registered andfalse
for unregistered (default)
Throws -> {Error} "ExecutionPermissions: instance not initialized"
Set registration state for referenced contract instance
Source
contracts/ExecutionPermissions.sol
--setRegistered(bool)
contracts/interfaces/IExecutionPermissions.sol
--setRegistered(bool)
Parameters
ref
{address} Contract instance owned bymsg.sender
state
{boolean} Settrue
for registered andfalse
for unregistered (default)
Throws -> {Error} "ExecutionPermissions: instance not initialized"
Throws -> {Error} "ExecutionPermissions: instance does not implement
.owner()"
Throws -> {Error} "ExecutionPermissions: not instance owner"
Show some support developers of this contract
Source
Allow owner of
ExecutionPermissions
to receive tips
Source
contracts/ExecutionPermissions.sol
--withdraw(address,uint256)
contracts/interfaces/IExecutionPermissions.sol
--withdraw(address,uint256)
Parameters
to
{address} Where to send Ethereumamount
{uint256} Measured in Wei
Throws -> {Error} "ExecutionPermissions: caller not owner"
Throws -> {Error} "ExecutionPermissions: transfer failed"
Initiate transfer of contract ownership
Source
contracts/ExecutionPermissions.sol
--nominateOwner(address)
contracts/interfaces/IExecutionPermissions.sol
--nominateOwner(address)
Parameters
newOwner
{address} Account that may claim ownership of contract
Throws -> {Error} "ExecutionPermissions: caller not owner"
Throws -> {Error} "ExecutionPermissions: new owner cannot be zero address"
Accept transfer of contract ownership
Source
contracts/ExecutionPermissions.sol
--claimOwnership()
contracts/interfaces/IExecutionPermissions.sol
--claimOwnership()
Throws -> {Error} "ExecutionPermissions: new owner cannot be zero address"
Throws -> {Error} "ExecutionPermissions: sender not nominated"
Check execution permissions of referenced contract function for given caller
Source
contracts/ExecutionPermissions.sol
--permissions(address,bytes4,address)
contracts/interfaces/IExecutionPermissions.sol
--permissions(address,bytes4,address)
Parameters
ref
{address} Contract address withtarget
functiontarget
{bytes4} Function ID to checkcaller
{address} Originalmsg.sender
of targeted function
Check registration status of referenced contract
Source
contracts/ExecutionPermissions.sol
--registered(address,bool)
contracts/interfaces/IExecutionPermissions.sol
--registered(address,bool)
Parameters
ref
{address} Contract address to check registration state
Returns -> {boolean} State of ref
registration
Obtain current owner address
Source
contracts/ExecutionPermissions.sol
--owner()
contracts/interfaces/IExecutionPermissions.sol
--owner()
Returns -> {address} Current owner of contract instance
Obtain new owner nominated address
Source
contracts/ExecutionPermissions.sol
--nominated_owner()
contracts/interfaces/IExecutionPermissions.sol
--nominated_owner()
Returns -> {address} Last nominated address of new contract instance owner
This repository may not be feature complete and/or fully functional, Pull Requests that add features or fix bugs are certainly welcomed.
Options for contributing to execution-permissions and solidity-utilities
Start making a Fork of this repository to an account that you have write permissions for.
- Add remote for fork URL. The URL syntax is
git@github.com:<NAME>/<REPO>.git
...
cd ~/git/hub/solidity-utilities/execution-permissions
git remote add fork git@github.com:<NAME>/execution-permissions.git
- Commit your changes and push to your fork, eg. to fix an issue...
cd ~/git/hub/solidity-utilities/execution-permissions
git commit -F- <<'EOF'
:bug: Fixes #42 Issue
**Edits**
- `<SCRIPT-NAME>` script, fixes some bug reported in issue
EOF
git push fork main
Note, the
-u
option may be used to setfork
as the default remote, eg.git push -u fork main
however, this will also default thefork
remote for pulling from too! Meaning that pulling updates fromorigin
must be done explicitly, eg.git pull origin main
- Then on GitHub submit a Pull Request through the Web-UI, the URL syntax is
https://github.com/<NAME>/<REPO>/pull/new/<BRANCH>
Note; to decrease the chances of your Pull Request needing modifications before being accepted, please check the dot-github repository for detailed contributing guidelines.
Thanks for even considering it!
Via Liberapay you may [![sponsor__shields_io__liberapay]][sponsor__link__liberapay] on a repeating basis.
Regardless of if you're able to financially support projects such as execution-permissions that solidity-utilities maintains, please consider sharing projects that are useful with others, because one of the goals of maintaining Open Source repositories is to provide value to the community.
Utility contract for setting/enforcing execution permissions per function
Copyright (C) 2022 S0AndS0
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, version 3 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
For further details review full length version of AGPL-3.0 License.