-
Notifications
You must be signed in to change notification settings - Fork 28
YNU-786: feat: smart wallet support #580
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
base: main
Are you sure you want to change the base?
Changes from all commits
eb1f4e1
b5cfc03
849fa5e
d4939a4
1e0c02c
42d9143
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| { | ||
| "lib/forge-std": { | ||
| "rev": "1801b0541f4fda118a10798fd3486bb7051c5dd6" | ||
| }, | ||
| "lib/openzeppelin-contracts": { | ||
| "tag": { | ||
| "name": "v5.5.0", | ||
| "rev": "fcbae5394ae8ad52d8e580a3477db99814b9d565" | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,7 @@ import { | |
| VALIDATION_FAILURE | ||
| } from "../interfaces/ISignatureValidator.sol"; | ||
| import {EcdsaSignatureUtils} from "./EcdsaSignatureUtils.sol"; | ||
| import {SwSignatureUtils} from "./SwSignatureUtils.sol"; | ||
| import {Utils} from "../Utils.sol"; | ||
|
|
||
| /** | ||
|
|
@@ -36,6 +37,7 @@ function toSigningData(SessionKeyAuthorization memory skAuth) pure returns (byte | |
| * @notice Validator supporting session key delegation for temporary signing authority | ||
| * @dev Enables a participant to delegate signing authority to a session key with metadata. | ||
| * Useful for hot wallets, time-limited access, or gasless transactions. | ||
| * Supports both EOA (ECDSA) and smart contract wallet (ERC-1271/ERC-6492) signatures. | ||
| * | ||
| * Authorization Flow: | ||
| * 1. Participant signs a SessionKeyAuthorization to delegate to a session key | ||
|
|
@@ -45,7 +47,10 @@ function toSigningData(SessionKeyAuthorization memory skAuth) pure returns (byte | |
| * Signature Format: | ||
| * bytes sigBody = abi.encode(SessionKeyAuthorization skAuthorization, bytes signature) | ||
| * | ||
| * Where signature is a standard 65-byte EIP-191 or raw ECDSA signature of the packed state. | ||
| * Where signature can be: | ||
| * - Standard 65-byte EIP-191 or raw ECDSA signature (for EOAs) | ||
| * - ERC-1271 signature (for deployed smart wallets) | ||
| * - ERC-6492 signature (for undeployed smart wallets) | ||
| * | ||
| * Security Model: | ||
| * - Off-chain enforcement (Clearnode) should validate session key expiration and usage limits | ||
|
|
@@ -58,7 +63,8 @@ contract SessionKeyValidator is ISignatureValidator { | |
| * @dev Validates: | ||
| * 1. participant signed the SessionKeyAuthorization (with channelId binding) | ||
| * 2. sessionKey signed the full state message (channelId + signingData) | ||
| * Tries EIP-191 recovery first, then raw ECDSA for both signatures. | ||
| * Supports both EOA (ECDSA) and smart wallet (ERC-1271/ERC-6492) signatures. | ||
| * Tries ECDSA validation first, then smart wallet validation for both signatures. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Inaccurate "tries ECDSA first" description in two NatSpec comments. Both the ✏️ Suggested fixes- * Tries ECDSA validation first, then smart wallet validation for both signatures.
+ * Routes to smart wallet validation (ERC-1271/ERC-6492) if the signer has deployed code
+ * or the signature carries the ERC-6492 magic suffix; otherwise uses ECDSA.- * `@dev` Tries ECDSA validation first, then smart wallet validation
+ * `@dev` Routes to ERC-1271/ERC-6492 validation if the signer has deployed code or the signature
+ * is ERC-6492 formatted; otherwise falls back to ECDSA validation.Also applies to: 102-102 🤖 Prompt for AI Agents |
||
| * @param channelId The channel identifier to include in state messages | ||
| * @param signingData The encoded state data (without channelId or signatures) | ||
| * @param signature Encoded as abi.encode(SessionKeyAuthorization, bytes signature) | ||
|
|
@@ -70,24 +76,44 @@ contract SessionKeyValidator is ISignatureValidator { | |
| bytes calldata signingData, | ||
| bytes calldata signature, | ||
| address participant | ||
| ) external pure returns (ValidationResult) { | ||
| ) external returns (ValidationResult) { | ||
| (SessionKeyAuthorization memory skAuth, bytes memory skSignature) = | ||
| abi.decode(signature, (SessionKeyAuthorization, bytes)); | ||
|
|
||
| // Step 1: Verify participant authorized this session key | ||
| bytes memory authMessage = toSigningData(skAuth); | ||
| bool authResult = EcdsaSignatureUtils.validateEcdsaSigner(authMessage, skAuth.authSignature, participant); | ||
| bool authResult = _validateSigner(authMessage, skAuth.authSignature, participant); | ||
|
|
||
| if (!authResult) { | ||
| return VALIDATION_FAILURE; | ||
| } | ||
|
|
||
| // Step 2: Verify session key signed the full state message | ||
| bytes memory stateMessage = Utils.pack(channelId, signingData); | ||
| if (EcdsaSignatureUtils.validateEcdsaSigner(stateMessage, skSignature, skAuth.sessionKey)) { | ||
| if (_validateSigner(stateMessage, skSignature, skAuth.sessionKey)) { | ||
| return VALIDATION_SUCCESS; | ||
| } else { | ||
| return VALIDATION_FAILURE; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * @notice Validates a signature for a given signer (EOA or smart wallet) | ||
| * @dev Tries ECDSA validation first, then smart wallet validation | ||
| * @param message The message that was signed | ||
| * @param signature The signature to validate | ||
| * @param signer The expected signer's address | ||
| * @return bool True if signature is valid, false otherwise | ||
| */ | ||
| function _validateSigner(bytes memory message, bytes memory signature, address signer) | ||
| private | ||
| returns (bool) | ||
| { | ||
| if (signer.code.length != 0 || SwSignatureUtils.isERC6492Signature(signature)) { | ||
| // If signer has code or signature is ERC-6492, treat as smart wallet | ||
| return SwSignatureUtils.validateSmartWalletSigner(message, signature, signer); | ||
| } | ||
|
|
||
| return EcdsaSignatureUtils.validateEcdsaSigner(message, signature, signer); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| // SPDX-License-Identifier: MIT | ||
| pragma solidity 0.8.30; | ||
|
|
||
| import { | ||
| ISignatureValidator, | ||
| ValidationResult, | ||
| VALIDATION_SUCCESS, | ||
| VALIDATION_FAILURE | ||
| } from "../interfaces/ISignatureValidator.sol"; | ||
| import {SwSignatureUtils} from "./SwSignatureUtils.sol"; | ||
| import {Utils} from "../Utils.sol"; | ||
|
|
||
| /** | ||
| * @title SmartWalletValidator | ||
| * @notice Signature validator supporting smart contract wallets via ERC-4337 standards | ||
| * @dev Supports ERC-1271 and ERC-6492 signatures. | ||
| * | ||
| * The validator prepends channelId to the signingData to construct the full message, | ||
| * then attempts validation in the order listed above. | ||
| */ | ||
|
Comment on lines
+13
to
+20
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NatDoc mentions EOA support but the validator only handles smart wallets. Line 23 says "Validates a signature from either an EOA or smart contract wallet" but the implementation only calls 📝 Fix misleading documentation /**
* `@title` SmartWalletValidator
- * `@notice` Signature validator supporting smart contract wallets via ERC-4337 standards
+ * `@notice` Signature validator supporting smart contract wallets via ERC-1271 and ERC-6492 standards
* `@dev` Supports ERC-1271 and ERC-6492 signatures.
*
...
/**
- * `@notice` Validates a signature from either an EOA or smart contract wallet
+ * `@notice` Validates a signature from a smart contract wallet🤖 Prompt for AI Agents |
||
| contract SmartWalletValidator is ISignatureValidator { | ||
| /** | ||
| * @notice Validates a signature from either an EOA or smart contract wallet | ||
| * @dev Constructs the full message by prepending channelId to signingData, | ||
| * then tries validation in order: ERC-1271, ERC-6492 | ||
| * @param channelId The channel identifier to include in the signed message | ||
| * @param signingData The encoded state data (without channelId or signatures) | ||
| * @param signature The signature to validate (format varies by wallet type) | ||
| * @param participant The expected signer's address | ||
| * @return result VALIDATION_SUCCESS if valid, VALIDATION_FAILURE otherwise | ||
| */ | ||
| function validateSignature( | ||
| bytes32 channelId, | ||
| bytes calldata signingData, | ||
| bytes calldata signature, | ||
| address participant | ||
| ) external returns (ValidationResult) { | ||
| bytes memory message = Utils.pack(channelId, signingData); | ||
|
|
||
| if (SwSignatureUtils.validateSmartWalletSigner(message, signature, participant)) { | ||
| return VALIDATION_SUCCESS; | ||
| } else { | ||
| return VALIDATION_FAILURE; | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,125 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // SPDX-License-Identifier: MIT | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pragma solidity 0.8.30; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @title SwSignatureUtils | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @notice Utility library for Smart Wallet signature validation | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| library SwSignatureUtils { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using ECDSA for bytes32; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using MessageHashUtils for bytes; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bytes4 private constant ERC1271_MAGIC_VALUE = 0x1626ba7e; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bytes32 private constant ERC6492_MAGIC_SUFFIX = 0x6492649264926492649264926492649264926492649264926492649264926492; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @notice Thrown when ERC-6492 contract deployment fails | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param factory The factory address that failed to deploy | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param factoryCalldata The calldata that was used for deployment | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| error ERC6492DeploymentFailed(address factory, bytes factoryCalldata); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @notice Thrown when deployed contract has no code after ERC-6492 deployment | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param expectedSigner The address that should have been deployed | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| error ERC6492NoCode(address expectedSigner); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @notice Validates a signature from a smart contract wallet only (no ECDSA) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @dev Attempts validation in order: ERC-1271 (deployed), ERC-6492 (non-deployed) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param message The message that was signed (will be hashed internally) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param signature The signature to validate (format varies by wallet type) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param expectedSigner The smart contract wallet address | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @return bool True if signature is valid according to ERC-1271 or ERC-6492 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function validateSmartWalletSigner(bytes memory message, bytes memory signature, address expectedSigner) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| internal | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| returns (bool) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bytes32 messageHash = keccak256(message); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (expectedSigner.code.length > 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (isValidErc1271Signature(expectedSigner, messageHash, signature)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (isERC6492Signature(signature)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return isValidERC6492Signature(messageHash, signature, expectedSigner); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @notice Validates an ERC-1271 signature for a deployed smart contract wallet | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param signer The smart contract wallet address | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param hash The hash of the signed message | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param signature The signature bytes | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @return bool True if the contract returns the ERC-1271 magic value | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function isValidErc1271Signature(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try IERC1271(signer).isValidSignature(hash, signature) returns (bytes4 magicValue) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return magicValue == ERC1271_MAGIC_VALUE; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @notice Checks if a signature is wrapped in ERC-6492 format | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @dev ERC-6492 signatures end with the magic suffix | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param signature The signature to check | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @return bool True if signature contains ERC-6492 magic suffix | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function isERC6492Signature(bytes memory signature) internal pure returns (bool) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (signature.length < 32) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bytes32 suffix; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assembly { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| suffix := mload(add(signature, mload(signature))) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return suffix == ERC6492_MAGIC_SUFFIX; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @notice Checks the validity of a smart contract signature. If the expected signer has no code, it is deployed using the provided factory and calldata from the signature. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Otherwise, it checks the signature using the ERC-1271 standard. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param msgHash The hash of the message to verify the signature against | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param sig The signature to verify | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param expectedSigner The address of the expected signer | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @return True if the signature is valid, false otherwise or if signer is not a contract | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function isValidERC6492Signature(bytes32 msgHash, bytes memory sig, address expectedSigner) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| internal | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| returns (bool) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Extract the signature data (remove the magic suffix) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uint256 dataLength = sig.length - 32; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bytes memory signatureData = new bytes(dataLength); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (uint256 i = 0; i < dataLength; i++) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| signatureData[i] = sig[i]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+107
to
+112
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (address create2Factory, bytes memory factoryCalldata, bytes memory originalSig) = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| abi.decode(signatureData, (address, bytes, bytes)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (expectedSigner.code.length == 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (bool success,) = create2Factory.call(factoryCalldata); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| require(success, ERC6492DeploymentFailed(create2Factory, factoryCalldata)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| require(expectedSigner.code.length != 0, ERC6492NoCode(expectedSigner)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return IERC1271(expectedSigner).isValidSignature(msgHash, originalSig) == ERC1271_MAGIC_VALUE; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This call to |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+102
to
+124
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing
This asymmetry means a malformed ERC-6492 signature pointing to an incompatible contract will revert the whole on-chain operation (channel creation, deposit, etc.) rather than just failing validation. 🐛 Proposed fix: wrap in try/catch like the ERC-1271 path- return IERC1271(expectedSigner).isValidSignature(msgHash, originalSig) == ERC1271_MAGIC_VALUE;
+ return isValidErc1271Signature(expectedSigner, msgHash, originalSig);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Documentation describes validation order incorrectly.
The doc states ERC-6492 is tried first, then ERC-1271. The actual code in
SwSignatureUtils.validateSmartWalletSignerdoes the opposite: it checks ERC-1271 first (for deployed wallets), then falls back to ERC-6492.📝 Proposed fix to match the actual code
🤖 Prompt for AI Agents