Skip to content

Commit

Permalink
fix:code updates init for ERc7739 updates
Browse files Browse the repository at this point in the history
  • Loading branch information
livingrockrises committed Oct 29, 2024
1 parent d64df5c commit fa90983
Showing 1 changed file with 45 additions and 27 deletions.
72 changes: 45 additions & 27 deletions contracts/base/ERC7739Validator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -151,62 +151,80 @@ 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.
break
}
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);
}

Expand Down

0 comments on commit fa90983

Please sign in to comment.