Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions contracts/DataTypes.sol
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,9 @@ ValidationData constant ERC4337_VALIDATION_FAILED = ValidationData.wrap(1);
bytes4 constant EIP1271_SUCCESS = 0x1626ba7e;
bytes4 constant EIP1271_FAILED = 0xFFFFFFFF;

uint256 constant POLICYDATA_LENGTH_OFFSET = 32;
uint256 constant POLICYDATA_OFFSET = 64;

uint256 constant ERC7579_MODULE_TYPE_VALIDATOR = 1;
uint256 constant ERC7579_MODULE_TYPE_EXECUTOR = 2;
uint256 constant ERC7579_MODULE_TYPE_FALLBACK = 3;
Expand Down
71 changes: 35 additions & 36 deletions contracts/SmartSession.sol
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,7 @@ contract SmartSession is ISmartSession, SmartSessionBase, SmartSessionERC7739 {
* @param userOpHash The hash of the user operation
* @return vd ValidationData containing the validation result
*/
function validateUserOp(
PackedUserOperation calldata userOp,
bytes32 userOpHash
)
function validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash)
external
override
returns (ValidationData vd)
Expand Down Expand Up @@ -166,8 +163,7 @@ contract SmartSession is ISmartSession, SmartSessionBase, SmartSessionERC7739 {

// Enable ERC1271 policies
$enabledERC7739.enable({
contexts: enableData.sessionToEnable.erc7739Policies.allowedERC7739Content,
permissionId: permissionId
contexts: enableData.sessionToEnable.erc7739Policies.allowedERC7739Content, permissionId: permissionId
});

// Enabel ERC1271 policies
Expand All @@ -181,9 +177,7 @@ contract SmartSession is ISmartSession, SmartSessionBase, SmartSessionERC7739 {

// Enable action policies
$actionPolicies.enable({
permissionId: permissionId,
actionPolicyDatas: enableData.sessionToEnable.actions,
useRegistry: false
permissionId: permissionId, actionPolicyDatas: enableData.sessionToEnable.actions, useRegistry: false
});

_setPermit4337Paymaster(permissionId, enableData.sessionToEnable.permitERC4337Paymaster);
Expand Down Expand Up @@ -279,25 +273,27 @@ contract SmartSession is ISmartSession, SmartSessionBase, SmartSessionERC7739 {
// DEFAULT EXEC & BATCH CALL
else if (callType == CALLTYPE_BATCH) {
vd = vd.intersect(
$actionPolicies.actionPolicies.checkBatch7579Exec({
userOp: userOp,
permissionId: permissionId,
minPolicies: 1 // minimum of one actionPolicy must be set.
})
$actionPolicies.actionPolicies
.checkBatch7579Exec({
userOp: userOp,
permissionId: permissionId,
minPolicies: 1 // minimum of one actionPolicy must be set.
})
);
}
// DEFAULT EXEC & SINGLE CALL
else if (callType == CALLTYPE_SINGLE) {
(address target, uint256 value, bytes calldata callData) =
userOp.callData.decodeUserOpCallData().decodeSingle();
vd = vd.intersect(
$actionPolicies.actionPolicies.checkSingle7579Exec({
permissionId: permissionId,
target: target,
value: value,
callData: callData,
minPolicies: 1 // minimum of one actionPolicy must be set.
})
$actionPolicies.actionPolicies
.checkSingle7579Exec({
permissionId: permissionId,
target: target,
value: value,
callData: callData,
minPolicies: 1 // minimum of one actionPolicy must be set.
})
);
}
// DelegateCalls are not supported by SmartSession
Expand All @@ -319,7 +315,8 @@ contract SmartSession is ISmartSession, SmartSessionBase, SmartSessionERC7739 {
ActionId actionId = account.toActionId(bytes4(userOp.callData[:4]));

vd = vd.intersect(
$actionPolicies.actionPolicies[actionId].check({
$actionPolicies.actionPolicies[actionId]
.check({
permissionId: permissionId,
callOnIPolicy: abi.encodeCall(
IActionPolicy.checkAction,
Expand All @@ -332,7 +329,7 @@ contract SmartSession is ISmartSession, SmartSessionBase, SmartSessionERC7739 {
)
),
minPolicies: 1 // minimum of one actionPolicy must be set.
})
})
);
}

Expand All @@ -342,10 +339,7 @@ contract SmartSession is ISmartSession, SmartSessionBase, SmartSessionERC7739 {
// perform signature check with ISessionValidator
// this function will revert if no ISessionValidator is set for this permissionId
bool validSig = $sessionValidators.isValidISessionValidator({
hash: userOpHash,
account: account,
permissionId: permissionId,
signature: decompressedSignature
hash: userOpHash, account: account, permissionId: permissionId, signature: decompressedSignature
});

// if the ISessionValidator signature is invalid, the userOp is invalid
Expand All @@ -372,11 +366,7 @@ contract SmartSession is ISmartSession, SmartSessionBase, SmartSessionERC7739 {
* contentsType,
* uint16(contentsType.length))
*/
function isValidSignatureWithSender(
address sender,
bytes32 hash,
bytes calldata signature
)
function isValidSignatureWithSender(address sender, bytes32 hash, bytes calldata signature)
external
view
override
Expand Down Expand Up @@ -426,8 +416,7 @@ contract SmartSession is ISmartSession, SmartSessionBase, SmartSessionERC7739 {
{
bytes32 contentHash = string(contents).hashERC7739Content();
// isolate the PermissionId and actual signature from the supplied signature param
PermissionId permissionId = PermissionId.wrap(bytes32(signature[0:32]));
signature = signature[32:];
PermissionId permissionId = PermissionId.wrap(bytes32(signature[0:POLICYDATA_LENGTH_OFFSET]));

// forgefmt: disable-next-item
if (
Expand All @@ -437,25 +426,35 @@ contract SmartSession is ISmartSession, SmartSessionBase, SmartSessionERC7739 {
|| !$enabledERC7739.enabledContentNames[permissionId][appDomainSeparator].contains(msg.sender, contentHash)
) return false;

// Make sure signature length is sufficient
if (signature.length < POLICYDATA_OFFSET) return false;
// Extract the length of the policy data
uint256 policyDataLength = uint256(bytes32(signature[POLICYDATA_LENGTH_OFFSET:POLICYDATA_OFFSET]));
// Calculate remaining signature offset
uint256 remainingSignatureOffset = 64 + policyDataLength;

// check the ERC-1271 policy
bool valid = $erc1271Policies.checkERC1271({
account: msg.sender,
requestSender: sender,
hash: hash,
signature: signature,
signature: signature[POLICYDATA_OFFSET:remainingSignatureOffset], // extract policy data from the signature
permissionId: permissionId,
configId: permissionId.toErc1271PolicyId().toConfigId(),
minPoliciesToEnforce: 1
});

// if the erc1271 policy check failed, return false
if (!valid) return valid;

// Make sure signature length is sufficient
if (signature.length < remainingSignatureOffset) return false;
// this call reverts if the ISessionValidator is not set
return $sessionValidators.isValidISessionValidator({
hash: hash,
account: msg.sender,
permissionId: permissionId,
signature: signature
signature: signature[remainingSignatureOffset:] // extract the validator signature from the signature
});
}
}
24 changes: 10 additions & 14 deletions test/unit/base/ERC1271Base.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,20 @@ contract ERC1271TestBase is BaseTest {
bytes memory signature = abi.encodePacked(
t.r, t.s, t.v, appDomainSeparator, contents, contentsDescription, uint16(contentsDescription.length)
);
signature = abi.encodePacked(permissionId, signature);
signature = abi.encodePacked(
permissionId,
uint256(32),
bytes32(hex"b4b3b4b3b4b3b4b3b4b3b4b3b4b3b4b3b4b3b4b3b4b3b4b3b4b3b44204206969"),
signature
);
if (is6492) {
signature = _erc6492Wrap(signature);
}

// Success returns `0x1626ba7e`.
assertEq(
IERC1271(t.account).isValidSignature(
_toContentsHash(contents), abi.encodePacked(address(smartSession), signature)
),
IERC1271(t.account)
.isValidSignature(_toContentsHash(contents), abi.encodePacked(address(smartSession), signature)),
expectSuccess ? bytes4(0x1626ba7e) : bytes4(0xffffffff)
);
}
Expand All @@ -85,12 +89,7 @@ contract ERC1271TestBase is BaseTest {
);
}

function _toERC1271Hash(
address account,
bytes32 contents,
bytes memory contentsType,
bytes memory contentsName
)
function _toERC1271Hash(address account, bytes32 contents, bytes memory contentsType, bytes memory contentsName)
internal
view
returns (bytes32)
Expand Down Expand Up @@ -120,10 +119,7 @@ contract ERC1271TestBase is BaseTest {
return abi.encode(keccak256(bytes(t.name)), keccak256(bytes(t.version)), t.chainId, t.verifyingContract, t.salt);
}

function _typedDataSignTypeHash(
bytes memory contentsType,
bytes memory contentsName
)
function _typedDataSignTypeHash(bytes memory contentsType, bytes memory contentsName)
internal
pure
returns (bytes32)
Expand Down