# Developing the zerodev module
[TOC]
# Kernel V2 features
## Architecture change from v1
Major change from v1 is that we can now have 1) validator module and 2) execution module
What we have been using in v1 was that kernel only has `executeAndRevert` function to execute "any" external functions including delegate call.
And validation has to be done using the parameter of the `executeAndRevert` and that has been tricky for Kernel to limit the action with given parameters.
Instead, v2 has `validator module` and `execution module` to make things more clear on security wise.
What `execution module` does is adding functions to the `Kernel`, by using erc2535-style routing.
For example, you want to add the `transfer erc721` feature to `Kernel`, and add the limitation for session key to "only" enable the functionality to use that, this is what you can do.
- deploy contract that has transferring erc721 feature
```solidity
contract ERC721Transfer {
function transferERC721(address _token, address _to, uint256 _tokenId) external {
IERC721(_token).transferFrom(address(this), _to, _tokenId);
}
}
```
- deploy session key validation plugin
```solidity
contract SessionKeyValidationModule {
function validateUserOp(UserOperation _op, bytes32 _opHash, uint256 _missingFunds) external returns(uint256) {
// some validation logic
...
}
}
```
- register execution module with pairing validation module
```solidity
kernel.setExecution(ERC721Transfer.transferERC721.selector, address(erc721module), address(sessionModule))
```
you can also set the validator as address(0), which will fallback to defaultValidator
# validator module
## Storage rule
you'll need to make sure that you **only** touch the storage slot associated with the `msg.sender`.
associated storage is where the storage slot is calculated based on the address of the wallet.
it should follow the following rule
- slot == wallet address
- slot == `keccak(wallet address | X) + N`
so example of using the mapping properly is,
```solidity!
struct ValidatorStorage {
address owner;
uint256 validUntil;
...
}
mapping(address wallet => ValidatorStroage) public validatorStorage;
```
## Interface for IKernelValidator
```solidity!
interface IKernelValidator {
function enable(bytes calldata _data) external;
function disable(bytes calldata _data) external;
function validateUserOp(UserOperation calldata userOp, bytes32 userOpHash, uint256 missingFunds) external returns(uint256 validationData);
function validateSignature(bytes32 _hash, bytes calldata _signature) external view returns(uint256);
}
```
every `KernelValidator` should implement the `IKernelValidator` interface to be fully compatible with the `Kernel` v2.
### enable
enable function is for setting the initial data to interact with the validator.
For example, if you are implementing the single owner validator, enable function will look like
```solidity!
function enable(bytes calldata _data) external {
require(_data.length == 20, "!address");
validatorStorage[msg.sender].owner = address(bytes20(_data[0:20]));
}
```
### disable
disable function is for removing the data for some reason, maybe you want to revoke the session key for some reason, then this is the function you need to call in that case
```solidity!
function disable(bytes calldata _data) external {
require(_data.length == 20, "!address");
address key = address(bytes20(_data[0:20]));
validatorStorage[msg.sender].sessionKey[key] = false;
}
```
### validateUserOp
This function will act same as the IAccount.validateUserOp this will be called while account.validateUserOp and this will be forwarding all data except the userOp.signature, userOp.signature will be modified based on the mode of the validation
### validateSignature
This function will act as checking signature with the given validator module, if your validator does not expect to be used as defaultValidator, feel free not to implement this