Permissive
By Permissive LabsDocumentation
Supported accounts
Future accounts supported
Deployments
FeeManager impl: 0x84f066969d27c5A41F497f797B331C1c6973a91e
PermissionRegistry impl: 0xb8228206b5ABE05a41639669f33D2a87B9894803
PermissionExecutor impl: 0x36118380bA22ebEd531FBC1Cbec107a8b812F59a
PermissionVerifier impl: 0x54580F79b56DFf099bB6d7CAfB38D5E05F007bFD
FeeManager: 0x4cdb220B27b86161a2e82e2A29A45A37CF24765F
PermissionRegistry: 0xEa4c56AeEf09fdC5a2011faa29226877B9919CEC
PermissionExecutor: 0x878f23FD2489E5B0e0D28EA475852c09183FfC1A
PermissionVerifier: 0x141A637e4516A7B03b6B7530d6498aC9A6986028
===================================================================
ZerodevValidator impl: 0x504b2220f329d274c639e7f73243088c93f4f834
ZerodevValidator: 0xd464Fc6C1Fc5855B2F86A9a154Ee2C23b8C5b299
-------------------------------------------------------------------
BiconomyModule impl: 0x4Ba320EA20d862A773107fcf471F6702931D2366
BiconomyModule: 0x40292C57F0D74E3078211D53C5B1EB512B4d9bC7
-------------------------------------------------------------------
SafeModule impl: 0xe915390C3E2F72687a954364b5BA6362Ef12E33f
SafeModule: 0x84C01a3Ad6362622d88233254ED06F54B445437b
-------------------------------------------------------------------
6900 OperationValidator impl: 0x066811D72BA155F154C245278E1432b1BE40A55B
6900 OperationValidator: 0x0D6d6FD586524007F09A7B3cB4a2873ED940a308
-------------------------------------------------------------------
Saf4337Module impl: 0xc83F407Bc8456025CE674EEE1894A709dFb92f97
Safe4337Module: 0x389C72e17d0C885D8f80462f32A8A8a44680Bad3
-------------------------------------------------------------------
Contents
FeeManager
Inherits: Ownable
Author: Flydexo - @Flydex0
Permissive core contracts that determines the percent of gas fee that is collected by Permissive and collects the fees
State Variables
fee
100 basis point, 100 = 1%, 2000 = 20%
uint24 public fee = 2000;
initialized
needs initialization because owner is set as the CREATE2 deployer in the constructor
bool initialized;
Functions
initialize
initialize - Initialization function to set the real owner, see CREATE2
function initialize(address owner) external;
Parameters
Name | Type | Description |
---|---|---|
owner | address | The future owner of the FeeManager |
setFee
setFee - Sets the Permissive fee, only callable by the owner
function setFee(uint24 _fee) external;
Parameters
Name | Type | Description |
---|---|---|
_fee | uint24 | The new fee (100 basis point) |
pay
Function called to pay the FeeManager
used a function to avoid gas details in the core contracts
function pay() external payable;
Events
FeePaid
FeePaid - Emitted when the Permissive fee is collected
event FeePaid(address indexed from, uint256 amount);
PermissionExecutor
Inherits: IPermissionExecutor
see {IPermissionExecutor}
State Variables
feeManager
FeeManager private immutable feeManager;
Functions
constructor
constructor(FeeManager _feeManager);
execute
function execute(
address dest,
uint256 value,
bytes calldata func,
Permission calldata permission,
bytes32[] calldata,
uint256 gasFee
) external;
PermissionRegistry
Inherits: IPermissionRegistry
see {IPermissionRegistry}
State Variables
operatorPermissions
mapping(address sender => mapping(address operator => bytes32 permHash)) public operatorPermissions;
remainingPermUsage
mapping(address sender => mapping(bytes32 permHash => uint256 remainingUsage)) public remainingPermUsage;
Functions
constructor
constructor();
setRemainingPermUsage
function setRemainingPermUsage(bytes32 permHash, uint256 remainingUsage) external;
setOperatorPermissions
function setOperatorPermissions(address operator, bytes32 root) external;
PermissionVerifier
Inherits: IPermissionVerifier
see {IPermissionVerifier}
State Variables
permissionRegistry
PermissionRegistry immutable permissionRegistry;
Functions
constructor
constructor(PermissionRegistry registry);
verify
function verify(UserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds)
external
returns (uint256 validationData);
computeGasFee
function computeGasFee(UserOperation memory userOp) public pure returns (uint256 fee);
_validateFee
function _validateFee(UserOperation calldata userOp, uint256 providedFee) internal pure;
_validationData
function _validationData(UserOperation calldata userOp, bytes32 userOpHash, Permission memory permission)
internal
view
returns (uint256 validationData);
_validateData
function _validateData(
UserOperation calldata userOp,
bytes32 userOpHash,
uint256 missingAccountFunds,
Permission memory permission
) internal;
_validatePermission
function _validatePermission(
address to,
uint256 value,
bytes memory callData,
UserOperation calldata userOp,
Permission memory permission,
bytes32 permHash
) internal;
_validateMerklePermission
function _validateMerklePermission(Permission memory permission, bytes32[] memory proof, bytes32 permHash)
internal
view;
Constants
SIG_VALIDATION_FAILED
uint256 constant SIG_VALIDATION_FAILED = 1;
Contents
Contents
OperationValidator
State Variables
permissionVerifier
PermissionVerifier immutable permissionVerifier;
Functions
constructor
constructor(PermissionVerifier _verifier);
validateUserOp
function validateUserOp(UserOperation calldata userOp, bytes32 userOpHash) external returns (uint256 validationData);
Contents
BiconomyAuthorizationModule
Inherits: BaseAuthorizationModule
State Variables
permissionVerifier
PermissionVerifier immutable permissionVerifier;
permissionExecutor
PermissionExecutor immutable permissionExecutor;
Functions
constructor
constructor(PermissionVerifier _verifier, PermissionExecutor _executor);
validateUserOp
function validateUserOp(UserOperation memory userOp, bytes32 userOpHash) external returns (uint256 validationData);
execute
function execute(
address dest,
uint256 value,
bytes memory func,
Permission calldata permission,
bytes32[] calldata proof,
uint256 gasFee
) external;
isValidSignature
function isValidSignature(bytes32 _dataHash, bytes memory _signature) public view override returns (bytes4);
Contents
ISafe
Functions
execTransactionFromModuleReturnData
function execTransactionFromModuleReturnData(address to, uint256 value, bytes memory data, Operation operation)
external
returns (bool success, bytes memory returnData);
Enums
Operation
enum Operation {
Call,
DelegateCall
}
Safe4337Module
Inherits: SafeStorage
State Variables
myAddress
address immutable myAddress;
entryPoint
IEntryPoint immutable entryPoint;
permissionVerifier
PermissionVerifier immutable permissionVerifier;
permissionExecutor
PermissionExecutor immutable permissionExecutor;
SENTINEL_MODULES
address internal constant SENTINEL_MODULES = address(0x1);
Functions
constructor
constructor(IEntryPoint _entryPoint, PermissionVerifier verifier, PermissionExecutor executor);
validateUserOp
function validateUserOp(UserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds)
external
returns (uint256 validationData);
execute
function execute(
address dest,
uint256 value,
bytes memory func,
Permission calldata permission,
bytes32[] calldata proof,
uint256 gasFee
) external;
enableMyself
function enableMyself() public;
_payPrefund
function _payPrefund(uint256 missingAccountFunds) internal;
receive
receive() external payable;
_onlySafe
function _onlySafe() internal view;
Events
OperatorMutated
event OperatorMutated(address indexed operator, bytes32 indexed oldPermissions, bytes32 indexed newPermissions);
PermissionVerified
event PermissionVerified(bytes32 indexed userOpHash, UserOperation userOp);
PermissionUsed
event PermissionUsed(
bytes32 indexed permHash, address dest, uint256 value, bytes func, Permission permission, uint256 gasFee
);
NewSafe
event NewSafe(address safe);
SafeModule
State Variables
safe
ISafe public safe;
entryPoint
IEntryPoint immutable entryPoint;
permissionVerifier
PermissionVerifier immutable permissionVerifier;
permissionExecutor
PermissionExecutor immutable permissionExecutor;
Functions
constructor
constructor(IEntryPoint _entryPoint, PermissionVerifier _verifier, PermissionExecutor _executor);
setSafe
function setSafe(address _safe) external;
validateUserOp
function validateUserOp(UserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds)
external
returns (uint256 validationData);
execute
function execute(
address dest,
uint256 value,
bytes memory func,
Permission calldata permission,
bytes32[] calldata proof,
uint256 gasFee
) external;
executeAsModule
function executeAsModule(address dest, uint256 value, bytes memory data) external;
_requireFromEntryPointOrOwner
function _requireFromEntryPointOrOwner() internal view;
_payPrefund
function _payPrefund(uint256 missingAccountFunds) internal;
receive
receive() external payable;
_onlySafe
function _onlySafe() internal view;
Events
OperatorMutated
event OperatorMutated(address indexed operator, bytes32 indexed oldPermissions, bytes32 indexed newPermissions);
PermissionVerified
event PermissionVerified(bytes32 indexed userOpHash, UserOperation userOp);
PermissionUsed
event PermissionUsed(
bytes32 indexed permHash, address dest, uint256 value, bytes func, Permission permission, uint256 gasFee
);
NewSafe
event NewSafe(address safe);
Contents
ZerodevValidator
Inherits: IKernelValidator
State Variables
permissionVerifier
PermissionVerifier immutable permissionVerifier;
Functions
constructor
constructor(PermissionVerifier verifier);
enable
function enable(bytes calldata) external override;
disable
function disable(bytes calldata) external pure override;
validateUserOp
function validateUserOp(UserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds)
external
override
returns (uint256 validationData);
validateSignature
function validateSignature(bytes32 hash, bytes calldata signature) external view override returns (uint256);
Contents
IDataValidator
Author: Flydexo - @Flydex0
This can be used for example to track the amount of granted ERC20 spent / swapped, etc...
The DataValidator contract must respect ERC-4337 storage rules. That means the only storage accessible must have the userOp.sender as key.
see https://eips.ethereum.org/EIPS/eip-4337#simulation
Functions
isValidData
isValidData is called in the validateUserOp function of the PermissionVerifier contract
userOp is formatted as integration agnostic, that means that if the SA (eg. Zerodev) requires a special field in the signature to determine which plugin to use, it is removed. Then the PermissionVerifier is called.
function isValidData(UserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds)
external
returns (bool success);
Parameters
Name | Type | Description |
---|---|---|
userOp | UserOperation | The userOp |
userOpHash | bytes32 | The userOp hash |
missingAccountFunds | uint256 | The funds the sender needs to pay to the EntryPoint |
Returns
Name | Type | Description |
---|---|---|
success | bool | Can revert to add additional logs and returns true if the userOp is considered valid |
IPermissionExecutor
Author: Flydexo - @Flydex0
The core contract in change or executing the userOperation after paying the FeeManager and transforming the AllowanceCalldata to ABI
Functions
execute
Execute a permissioned userOperation
function execute(
address dest,
uint256 value,
bytes calldata func,
Permission calldata permission,
bytes32[] calldata proof,
uint256 gasFee
) external;
Parameters
Name | Type | Description |
---|---|---|
dest | address | The called contract |
value | uint256 | The msg.value |
func | bytes | The AllowanceCalldata used to call the contract |
permission | Permission | The permission object |
proof | bytes32[] | |
gasFee | uint256 | The fee for the userOperation (used to compute the Permissive fee) |
Events
PermissionUsed
PermissionUsed - When a permissioned userOperation passed with success
event PermissionUsed(
bytes32 indexed permHash, address dest, uint256 value, bytes func, Permission permission, uint256 gasFee
);
IPermissionRegistry
Author: Flydexo - @Flydex0
PermissionRegistry stores the permissions of an operator on an account and the remaining usages of a permission on an account.
Functions
operatorPermissions
operatorPermissions - Getter for the granted permissions of an operator on an account
function operatorPermissions(address sender, address operator) external view returns (bytes32 permHash);
Parameters
Name | Type | Description |
---|---|---|
sender | address | The account address |
operator | address | The operator address |
remainingPermUsage
remainingPermUsage - Getter for the remaining usage of a permission on an account (usage + 1)
function remainingPermUsage(address sender, bytes32 permHash) external view returns (uint256 remainingUsage);
Parameters
Name | Type | Description |
---|---|---|
sender | address | The account address |
permHash | bytes32 | The permission hash |
setOperatorPermissions
setOperatorPermissions - Setter for the granted permissions of an operator on an account. Can only be called by the account modifying it's own operator permissions.
function setOperatorPermissions(address operator, bytes32 root) external;
Parameters
Name | Type | Description |
---|---|---|
operator | address | The operator address |
root | bytes32 | The permissions merkle root |
setRemainingPermUsage
setRemainingPermUsage - Setter for the remaining usage of a permission on an account. Can only be called by the account modifying it's own usage
function setRemainingPermUsage(bytes32 permHash, uint256 remainingUsage) external;
Parameters
Name | Type | Description |
---|---|---|
permHash | bytes32 | The permission hash |
remainingUsage | uint256 | The permission remaining usage (usage + 1) |
Events
OperatorMutated
OperatorMutated - Emitted when the granted permisssions for an operator on an account change
event OperatorMutated(address indexed operator, bytes32 indexed oldPermissions, bytes32 indexed newPermissions);
IPermissionVerifier
Author: Flydexo - @Flydex0
Contract only callable with delegatecall by the account itself or it's module or plugin
Functions
verify
verify - Function that make all the Permissive related checks on the userOperation.
For validationData specs see see https://eips.ethereum.org/EIPS/eip-4337#definitions
function verify(UserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds)
external
returns (uint256 validationData);
Parameters
Name | Type | Description |
---|---|---|
userOp | UserOperation | The userOperation |
userOpHash | bytes32 | The userOperation hash |
missingAccountFunds | uint256 | The funds the sender needs to pay to the EntryPoint |
Returns
Name | Type | Description |
---|---|---|
validationData | uint256 | The validation data that signals are valid / invalid signature and the timespan of the permission |
computeGasFee
computeGasFee - Function called to compute the gasFee of the userOperation depending on all the gas parameters of the operation.
Use this function to determine the fee in the execute function
function computeGasFee(UserOperation memory userOp) external pure returns (uint256 fee);
Parameters
Name | Type | Description |
---|---|---|
userOp | UserOperation | The userOperation |
Events
PermissionVerified
PermissionVerified - Emitted when a permission is successfully verified
event PermissionVerified(bytes32 indexed userOpHash, UserOperation userOp);
Contents
AllowanceCalldata
Author: Flydexo - @Flydex0
Library in charge of verifying that the calldata is valid corresponding the the allowed calldata conditions.
Functions
isAllowedCalldata
isAllowedCalldata - checks the calldata is valid corresponding the the allowed calldata conditions.
To check the msg.value field, the first arg of data must be equal to msg.value and the first arg of allowed calldata must set rules for the value
function isAllowedCalldata(bytes memory allowed, bytes memory data, uint256 value) internal view returns (bool isOk);
Parameters
Name | Type | Description |
---|---|---|
allowed | bytes | The RLP encoded Allowed calldata |
data | bytes | The RLP encodedx calldata |
value | uint256 | The msg.value |
Returns
Name | Type | Description |
---|---|---|
isOk | bool | In case of success returns true, otherwise fails or reverts |
RLPtoABI
RLPToABI - Transform the RLP encoded calldata into ABI
the RLP calldata must already be ABI compatible when all arguments are concatenated
If you have n arguments to verify (including value)
You need to have n arguments in the RLP calldata
And when concatenated, the arguments must be ABI compatible
So if you have 1 argument to check (ignore value for the example)
it must be RLP.encode([abi.encode(argument)])
function RLPtoABI(bytes memory data) internal pure returns (bytes memory abiEncoded);
Parameters
Name | Type | Description |
---|---|---|
data | bytes | the RLP encoded calldata |
Returns
Name | Type | Description |
---|---|---|
abiEncoded | bytes | The result ABI encoded, is valid calldata |
_validateArguments
_validateArguments - Core function of the AllowanceCalldata library, checks if arguments respect the allowedArguments conditions
isOr is used to do the minimum checks
in case of AND = a single false result breaks
in case of OR = a single true result breaks
function _validateArguments(
RLPReader.RLPItem[] memory allowedArguments,
RLPReader.RLPItem[] memory arguments,
bool isOr
) internal view returns (bool canPass);
Parameters
Name | Type | Description |
---|---|---|
allowedArguments | RLPReader.RLPItem[] | The allowed arguments |
arguments | RLPReader.RLPItem[] | The arguments |
isOr | bool | Is the current loop in a or condition |
_unsafe_inc
optimized incrementation
function _unsafe_inc(uint256 i) private pure returns (uint256);
_fillArray
_fillArray - Creates a new array filled with the same item
function _fillArray(RLPReader.RLPItem[] memory arguments, uint256 index, uint256 length)
internal
pure
returns (RLPReader.RLPItem[] memory newArguments);
Parameters
Name | Type | Description |
---|---|---|
arguments | RLPReader.RLPItem[] | Array of arguments to take the item from |
index | uint256 | The index of the item to fill with |
length | uint256 | The length of the new filled array |
Constants
ANY
uint256 constant ANY = 0;
NE
uint256 constant NE = 1;
EQ
uint256 constant EQ = 2;
GT
uint256 constant GT = 3;
LT
uint256 constant LT = 4;
AND
uint256 constant AND = 5;
OR
uint256 constant OR = 6;
Permission
Author: Flydexo - @Flydex0
A permission is made for a specific function of a specific contract
1 operator = 1 permission set
1 permission set = infinite permissions
struct Permission {
address operator;
address to;
bytes4 selector;
bytes allowed_arguments;
address paymaster;
uint48 validUntil;
uint48 validAfter;
uint256 maxUsage;
address dataValidator;
}
PermissionLib
Author: Flydexo - @Flydex0
Library used to hash the Permission struct
Functions
hash
function hash(Permission memory permission) internal pure returns (bytes32 permHash);