From fa909831d2ca5811bf793589f61236be5c2d9a8c Mon Sep 17 00:00:00 2001 From: livingrockrises <90545960+livingrockrises@users.noreply.github.com> Date: Tue, 29 Oct 2024 11:19:34 +0530 Subject: [PATCH] fix:code updates init for ERc7739 updates --- contracts/base/ERC7739Validator.sol | 72 ++++++++++++++++++----------- 1 file changed, 45 insertions(+), 27 deletions(-) diff --git a/contracts/base/ERC7739Validator.sol b/contracts/base/ERC7739Validator.sol index 1c97dae6..46bde443 100644 --- a/contracts/base/ERC7739Validator.sol +++ b/contracts/base/ERC7739Validator.sol @@ -151,54 +151,71 @@ abstract contract ERC7739Validator is IERC7739 { /// We want to create bazaars, not walled castles. /// And we'll use push the Turing Completeness of the EVM to the limits to do so. function _erc1271IsValidSignatureViaNestedEIP712(bytes32 hash, bytes calldata signature) internal view virtual returns (bool result) { - bytes32 t = _typedDataSignFieldsForAccount(msg.sender); + // Review + // bytes32 tfa = _typedDataSignFieldsForAccount(msg.sender); + bytes calldata contents = signature; + uint256 t = uint256(uint160(address(this))); + // Forces the compiler to pop the variables after the scope, avoiding stack-too-deep. + if (t != uint256(0)) { + (, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt,) = + EIP712(msg.sender).eip712Domain(); + /// @solidity memory-safe-assembly + assembly { + t := mload(0x40) // Grab the free memory pointer. + // Skip 2 words for the `typedDataSignTypehash` and `contents` struct hash. + mstore(add(t, 0x40), keccak256(add(name, 0x20), mload(name))) + mstore(add(t, 0x60), keccak256(add(version, 0x20), mload(version))) + mstore(add(t, 0x80), chainId) + mstore(add(t, 0xa0), shr(96, shl(96, verifyingContract))) + mstore(add(t, 0xc0), salt) + mstore(0x40, add(t, 0xe0)) // Allocate the memory. + } + } /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. - // `c` is `contentsType.length`, which is stored in the last 2 bytes of the signature. + // `c` is `contentsDescription.length`, which is stored in the last 2 bytes of the signature. let c := shr(240, calldataload(add(signature.offset, sub(signature.length, 2)))) for {} 1 {} { let l := add(0x42, c) // Total length of appended data (32 + 32 + c + 2). let o := add(signature.offset, sub(signature.length, l)) // Offset of appended data. mstore(0x00, 0x1901) // Store the "\x19\x01" prefix. calldatacopy(0x20, o, 0x40) // Copy the `APP_DOMAIN_SEPARATOR` and `contents` struct hash. - // Use the `PersonalSign` workflow if the reconstructed hash doesn't match, - // or if the appended data is invalid, i.e. - // `appendedData.length > signature.length || contentsType.length == 0`. - if or(xor(keccak256(0x1e, 0x42), hash), or(lt(signature.length, l), iszero(c))) { - t := 0 // Set `t` to 0, denoting that we need to `hash = _hashTypedData(hash)`. - mstore(t, _PERSONAL_SIGN_TYPEHASH) - mstore(0x20, hash) // Store the `prefixed`. - hash := keccak256(t, 0x40) // Compute the `PersonalSign` struct hash. - break - } - // Else, use the `TypedDataSign` workflow. + // Only use the `TypedDataSign` workflow. // `TypedDataSign({ContentsName} contents,bytes1 fields,...){ContentsType}`. mstore(m, "TypedDataSign(") // Store the start of `TypedDataSign`'s type encoding. let p := add(m, 0x0e) // Advance 14 bytes to skip "TypedDataSign(". - calldatacopy(p, add(o, 0x40), c) // Copy `contentsType` to extract `contentsName`. + calldatacopy(p, add(o, 0x40), c) // Copy `contentsName`, optimistically. + contents.offset := add(o, 0x40) // Set the offset of `contents`. + contents.length := c // Set the length of `contents`. + mstore(add(p, c), 40) // Store a '(' after the end. + if iszero(eq(byte(0, mload(sub(add(p, c), 1))), 41)) { + let e := 0 // Length of `contentsName` in explicit mode. + for { let q := sub(add(p, c), 1) } 1 { } { + e := add(e, 1) // Scan backwards until we encounter a ')'. + if iszero(gt(lt(e, c), eq(byte(0, mload(sub(q, e))), 41))) { break } + } + c := sub(c, e) // Truncate `contentsDescription` to `contentsType`. + calldatacopy(p, add(add(o, 0x40), c), e) // Copy `contentsName`. + mstore8(add(p, e), 40) // Store a '(' exactly right after the end. + } // `d & 1 == 1` means that `contentsName` is invalid. let d := shr(byte(0, mload(p)), 0x7fffffe000000000000010000000000) // Starts with `[a-z(]`. - // Store the end sentinel '(', and advance `p` until we encounter a '(' byte. - for { - mstore(add(p, c), 40) - } iszero(eq(byte(0, mload(p)), 40)) { - p := add(p, 1) - } { + // Advance `p` until we encounter '('. + for { } iszero(eq(byte(0, mload(p)), 40)) { p := add(p, 1) } { d := or(shr(byte(0, mload(p)), 0x120100000001), d) // Has a byte in ", )\x00". } - mstore(p, " contents,bytes1 fields,string n") // Store the rest of the encoding. - mstore(add(p, 0x20), "ame,string version,uint256 chain") - mstore(add(p, 0x40), "Id,address verifyingContract,byt") - mstore(add(p, 0x60), "es32 salt,uint256[] extensions)") - p := add(p, 0x7f) + mstore(p, " contents,string name,string") // Store the rest of the encoding. + mstore(add(p, 0x1c), " version,uint256 chainId,address") + mstore(add(p, 0x3c), " verifyingContract,bytes32 salt)") + p := add(p, 0x5c) calldatacopy(p, add(o, 0x40), c) // Copy `contentsType`. // Fill in the missing fields of the `TypedDataSign`. calldatacopy(t, o, 0x40) // Copy the `contents` struct hash to `add(t, 0x20)`. mstore(t, keccak256(m, sub(add(p, c), m))) // Store `typedDataSignTypehash`. // The "\x19\x01" prefix is already at 0x00. // `APP_DOMAIN_SEPARATOR` is already at 0x20. - mstore(0x40, keccak256(t, 0x120)) // `hashStruct(typedDataSign)`. + mstore(0x40, keccak256(t, 0xe0)) // `hashStruct(typedDataSign)`. // Compute the final hash, corrupted if `contentsName` is invalid. hash := keccak256(0x1e, add(0x42, and(1, d))) signature.length := sub(signature.length, l) // Truncate the signature. @@ -206,7 +223,8 @@ abstract contract ERC7739Validator is IERC7739 { } mstore(0x40, m) // Restore the free memory pointer. } - if (t == bytes32(0)) hash = _hashTypedDataForAccount(msg.sender, hash); // `PersonalSign` workflow. + // Review + // if (tfa == bytes32(0)) hash = _hashTypedDataForAccount(msg.sender, hash); // `PersonalSign` workflow. result = _erc1271IsValidSignatureNowCalldata(hash, signature); }