Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add samples directory and custom session key plugins #22

Merged
merged 41 commits into from
Feb 16, 2024

Conversation

sm-stack
Copy link
Contributor

@sm-stack sm-stack commented Jan 8, 2024

Motivation

While there are basic plugins like SingleOwnerPlugin in src/plugins folder, it is not sufficient to show the different practices of plugins and the functionalities of ERC-6900. To enhance the understanding and utilization of ERC-6900 among plugin developers, establishing directories for various plugins would be beneficial.

Solution

This involves creating two new directories: src/samples/plugins and test/samples/plugins. These directories would host a range of plugins, showcasing the different capabilities and practices within the ERC-6900 framework.

Also add a custom session key plugin inside them, which demonstrates the usage of dependency and executeFromPluginExternal.

@jaypaik
Copy link
Collaborator

jaypaik commented Jan 10, 2024

Thanks @sm-stack ! I plan on merging in the latest iteration of our address associated storage libraries soon. You'll be able to use that here instead of the PluginStorageLib currently included here. Stay tuned!

Update: #23

@sm-stack
Copy link
Contributor Author

Update: #23

Updated some parts of the implementation with new PluginStorageLib!

Copy link
Collaborator

@jaypaik jaypaik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Took a pass, thanks for your patience here! Some ERC updates in flight too, so I imagine we'll need to work through some rebases.

src/samples/plugins/ModularSessionKeyPlugin.sol Outdated Show resolved Hide resolved
src/samples/plugins/interfaces/ISessionKeyPlugin.sol Outdated Show resolved Hide resolved
src/samples/plugins/ModularSessionKeyPlugin.sol Outdated Show resolved Hide resolved
src/samples/plugins/ModularSessionKeyPlugin.sol Outdated Show resolved Hide resolved
src/samples/plugins/ModularSessionKeyPlugin.sol Outdated Show resolved Hide resolved
src/samples/plugins/TokenSessionKeyPlugin.sol Outdated Show resolved Hide resolved
test/samples/plugins/ModularSessionKeyPlugin.t.sol Outdated Show resolved Hide resolved
src/samples/plugins/interfaces/ISessionKeyPlugin.sol Outdated Show resolved Hide resolved
src/samples/plugins/interfaces/ISessionKeyPlugin.sol Outdated Show resolved Hide resolved
src/samples/plugins/ModularSessionKeyPlugin.sol Outdated Show resolved Hide resolved
@sm-stack
Copy link
Contributor Author

Took a pass, thanks for your patience here! Some ERC updates in flight too, so I imagine we'll need to work through some rebases.

Addressed all feedbacks you provided, with small fixes to maintain compatibility with recent changes in the spec.

src/samples/plugins/ModularSessionKeyPlugin.sol Outdated Show resolved Hide resolved
src/samples/plugins/ModularSessionKeyPlugin.sol Outdated Show resolved Hide resolved
test/samples/plugins/ModularSessionKeyPlugin.t.sol Outdated Show resolved Hide resolved
address(ownerPlugin), (uint8(ISingleOwnerPlugin.FunctionId.USER_OP_VALIDATION_OWNER))
);
modularSessionDependency[1] = FunctionReferenceLib.pack(
address(ownerPlugin), (uint8(ISingleOwnerPlugin.FunctionId.RUNTIME_VALIDATION_OWNER_OR_SELF))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
address(ownerPlugin), (uint8(ISingleOwnerPlugin.FunctionId.RUNTIME_VALIDATION_OWNER_OR_SELF))
address(ownerPlugin), uint8(ISingleOwnerPlugin.FunctionId.RUNTIME_VALIDATION_OWNER_OR_SELF)

}

/// @inheritdoc BasePlugin
function onUninstall(bytes calldata data) external override {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Area of improvement here would be to be able to clean up all of an account's session keys just based on msg.sender, without relying on what is passed into data. Ideally, the responsibility of proper cleanup lies with the plugin.

This is probably a larger change though. Feel free to tackle this later.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though it will add some gas overhead, this sounds necessary to keep the consistency in the storage of plugin. I added an additional mapping that stores the information of session key and allowed selector to implement this.

Comment on lines 169 to 172
if (validUntil != 0) {
return _packValidationData(false, validUntil, validAfter);
}
return _SIG_VALIDATION_FAILED;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delaying SIG_VALIDATION_FAILED like this helps with gas estimation from bundlers when using dummy signatures.

Suggested change
if (validUntil != 0) {
return _packValidationData(false, validUntil, validAfter);
}
return _SIG_VALIDATION_FAILED;
return _packValidationData(validUntil == 0, validUntil, validAfter);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That seems valid. Fixed it.

returns (uint256)
{
if (functionId == uint8(FunctionId.USER_OP_VALIDATION_TEMPORARY_OWNER)) {
(address signer,) = userOpHash.toEthSignedMessageHash().tryRecover(userOp.signature);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check the result of tryRecover, and if err != ECDSA.RecoverError.NoError, revert with InvalidSignature().

src/samples/plugins/ModularSessionKeyPlugin.sol Outdated Show resolved Hide resolved
{
if (functionId == uint8(FunctionId.RUNTIME_VALIDATION_TEMPORARY_OWNER)) {
bytes4 selector = bytes4(data[0:4]);
bytes memory key = address(msg.sender).allocateAssociatedStorageKey(0, 1);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit

Suggested change
bytes memory key = address(msg.sender).allocateAssociatedStorageKey(0, 1);
bytes memory key = msg.sender.allocateAssociatedStorageKey(0, 1);

src/samples/plugins/TokenSessionKeyPlugin.sol Show resolved Hide resolved
@sm-stack
Copy link
Contributor Author

@jaypaik Addressed all the comments you suggested!

Copy link
Contributor

@adam-alchemy adam-alchemy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! I left a few optional suggestions, feel free to either adopt them or not.

Comment on lines 359 to 370
function _castToBytes32(address addr, bytes4 b4) internal pure returns (bytes32 res) {
assembly {
res := or(shl(96, addr), b4)
}
}

function _castToAddressAndBytes4(bytes32 b32) internal pure returns (address addr, bytes4 b4) {
assembly {
addr := shr(96, b32)
b4 := and(b32, 0xFFFFFFFF)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These work as-is, but you could reduce the shift amount down to 32 (from 96) if you wanted to make it compact.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep that's valid! Fixed it.

/// @param _untils The times until which the owners are valid.
event SessionKeysAdded(
address indexed account,
address[] indexed sessionKeys,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a heads up, indexing an array will result in the hash of the entire array, rather than indexing on the elements within it: https://docs.soliditylang.org/en/v0.8.19/abi-spec.html#encoding-of-indexed-event-parameters.

This is OK to leave as-is, just flagging that it may behave differently than expected. An alternative is to not index this field, or to emit a SessionKeyAdded event for each key, though that is expensive in gas.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also think that this will lead to an unexpected behavior, so I just removed the indexed field at the arrays at the both events.

/// @param account The account whose session keys are updated.
/// @param sessionKeys The addresses of the session keys.
/// @param selectors The selectors of the functions that the session keys are allowed to call.
event SessionKeysRemoved(address indexed account, address[] indexed sessionKeys, bytes4[] selectors);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here as above ^

@sm-stack
Copy link
Contributor Author

@adam-alchemy Thanks for the feedbacks! Addressed to all of them.

Copy link
Collaborator

@jaypaik jaypaik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some final nits!

Also noticed you use unchecked { ++i; } in some places but not others. Would prefer those be consistent too!

Comment on lines 326 to 327
uint48 _validAfter,
uint48 _validUntil
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit:

Suggested change
uint48 _validAfter,
uint48 _validUntil
uint48 validAfter,
uint48 validUntil

Comment on lines 335 to 336
sessionInfo.validAfter = _validAfter;
sessionInfo.validUntil = _validUntil;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
sessionInfo.validAfter = _validAfter;
sessionInfo.validUntil = _validUntil;
sessionInfo.validAfter = validAfter;
sessionInfo.validUntil = validUntil;

Comment on lines 95 to 100
for (uint256 i = 0; i < manifest.dependencyInterfaceIds.length;) {
manifest.dependencyInterfaceIds[i] = type(IModularSessionKeyPlugin).interfaceId;
unchecked {
++i;
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just:

manifest.dependencyInterfaceIds[0] = ...
manifest.dependencyInterfaceIds[1] = ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's more straightforward, fixed it.

Comment on lines 32 to 39
/// @param _afters The times after which the owners are valid.
/// @param _untils The times until which the owners are valid.
event SessionKeysAdded(
address indexed account,
address[] sessionKeys,
bytes4[] selectors,
uint48[] _afters,
uint48[] _untils
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// @param _afters The times after which the owners are valid.
/// @param _untils The times until which the owners are valid.
event SessionKeysAdded(
address indexed account,
address[] sessionKeys,
bytes4[] selectors,
uint48[] _afters,
uint48[] _untils
/// @param afters The times after which the owners are valid.
/// @param untils The times until which the owners are valid.
event SessionKeysAdded(
address indexed account,
address[] sessionKeys,
bytes4[] selectors,
uint48[] afters,
uint48[] untils

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making _after to after leads to the following error

Expected ',' but got reserved keyword 'after'

So I changed all of it to validAfter, and same with all untils.

Comment on lines 16 to 20
/// @param _after The time after which the owner is valid.
/// @param _until The time until which the owner is valid.
event SessionKeyAdded(
address indexed account, address indexed sessionKey, bytes4 selector, uint48 _after, uint48 _until
);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// @param _after The time after which the owner is valid.
/// @param _until The time until which the owner is valid.
event SessionKeyAdded(
address indexed account, address indexed sessionKey, bytes4 selector, uint48 _after, uint48 _until
);
/// @param after The time after which the owner is valid.
/// @param until The time until which the owner is valid.
event SessionKeyAdded(
address indexed account, address indexed sessionKey, bytes4 selector, uint48 after, uint48 until
);

Comment on lines 59 to 61
/// @param _after The time after which the owner is valid.
/// @param _until The time until which the owner is valid.
function addSessionKey(address sessionKey, bytes4 allowedSelector, uint48 _after, uint48 _until) external;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// @param _after The time after which the owner is valid.
/// @param _until The time until which the owner is valid.
function addSessionKey(address sessionKey, bytes4 allowedSelector, uint48 _after, uint48 _until) external;
/// @param after The time after which the owner is valid.
/// @param until The time until which the owner is valid.
function addSessionKey(address sessionKey, bytes4 allowedSelector, uint48 after, uint48 until) external;

Comment on lines 75 to 81
/// @param _afters The times after which the owners are valid.
/// @param _untils The times until which the owners are valid.
function addSessionKeyBatch(
address[] calldata sessionKeys,
bytes4[] calldata allowedSelectors,
uint48[] calldata _afters,
uint48[] calldata _untils
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// @param _afters The times after which the owners are valid.
/// @param _untils The times until which the owners are valid.
function addSessionKeyBatch(
address[] calldata sessionKeys,
bytes4[] calldata allowedSelectors,
uint48[] calldata _afters,
uint48[] calldata _untils
/// @param afters The times after which the owners are valid.
/// @param untils The times until which the owners are valid.
function addSessionKeyBatch(
address[] calldata sessionKeys,
bytes4[] calldata allowedSelectors,
uint48[] calldata afters,
uint48[] calldata untils

Copy link
Collaborator

@jaypaik jaypaik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🥳

@jaypaik
Copy link
Collaborator

jaypaik commented Feb 16, 2024

Looks like lint failed, can you run forge fmt?

@sm-stack
Copy link
Contributor Author

Forgot it, just committed :) @jaypaik

@jaypaik jaypaik merged commit 8b863f2 into erc6900:main Feb 16, 2024
3 checks passed
@sm-stack sm-stack deleted the sample-with-session-key branch February 16, 2024 14:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants