Skip to content
Closed
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
Empty file modified .husky/pre-commit
100755 → 100644
Empty file.
3 changes: 3 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions .idea/account.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1,698 changes: 1,698 additions & 0 deletions .idea/caches/deviceStreaming.xml

Large diffs are not rendered by default.

117 changes: 117 additions & 0 deletions .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions .idea/codeStyles/codeStyleConfig.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/copilot.data.migration.ask2agent.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/markdown.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Empty file modified deploy/execute_config.sh
100755 → 100644
Empty file.
Empty file modified deploy/verify_config.sh
100755 → 100644
Empty file.
2 changes: 1 addition & 1 deletion lib/forge-std
Submodule forge-std updated 60 files
+1 −1 .github/CODEOWNERS
+6 −0 .github/dependabot.yml
+61 −31 .github/workflows/ci.yml
+6 −1 .github/workflows/sync.yml
+3 −3 CONTRIBUTING.md
+15 −13 README.md
+1 −1 RELEASE_CHECKLIST.md
+3 −12 foundry.toml
+2 −2 package.json
+2 −12 scripts/vm.py
+2 −2 src/Base.sol
+1 −1 src/Config.sol
+2 −2 src/LibVariable.sol
+2 −2 src/Script.sol
+28 −13 src/StdAssertions.sol
+24 −8 src/StdChains.sol
+13 −17 src/StdCheats.sol
+30 −10 src/StdConfig.sol
+2 −2 src/StdConstants.sol
+2 −2 src/StdError.sol
+22 −4 src/StdInvariant.sol
+4 −12 src/StdJson.sol
+6 −2 src/StdMath.sol
+13 −11 src/StdStorage.sol
+2 −2 src/StdStyle.sol
+10 −18 src/StdToml.sol
+6 −14 src/StdUtils.sol
+2 −4 src/Test.sol
+52 −43 src/Vm.sol
+10 −19 src/console.sol
+2 −2 src/console2.sol
+2 −2 src/interfaces/IERC1155.sol
+2 −2 src/interfaces/IERC165.sol
+2 −2 src/interfaces/IERC20.sol
+8 −8 src/interfaces/IERC4626.sol
+2 −2 src/interfaces/IERC6909.sol
+2 −2 src/interfaces/IERC721.sol
+7 −13 src/interfaces/IERC7540.sol
+8 −8 src/interfaces/IERC7575.sol
+3 −8 src/interfaces/IMulticall3.sol
+691 −1,380 src/safeconsole.sol
+2 −2 test/CommonBase.t.sol
+34 −5 test/Config.t.sol
+19 −1 test/LibVariable.t.sol
+2 −2 test/StdAssertions.t.sol
+24 −24 test/StdChains.t.sol
+19 −20 test/StdCheats.t.sol
+2 −2 test/StdConstants.t.sol
+3 −4 test/StdError.t.sol
+2 −2 test/StdJson.t.sol
+8 −8 test/StdMath.t.sol
+24 −27 test/StdStorage.t.sol
+2 −2 test/StdStyle.t.sol
+2 −2 test/StdToml.t.sol
+13 −13 test/StdUtils.t.sol
+3 −3 test/Vm.t.sol
+2 −4 test/compilation/CompilationScript.sol
+2 −4 test/compilation/CompilationScriptBase.sol
+2 −4 test/compilation/CompilationTest.sol
+2 −4 test/compilation/CompilationTestBase.sol
Empty file modified prep/check-bytecode-changes.js
100755 → 100644
Empty file.
30 changes: 15 additions & 15 deletions snapshots/BenchmarkTest.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@
"testERC20Transfer_ERC4337MinimalAccount": "171509",
"testERC20Transfer_ERC4337MinimalAccount_AppSponsor": "168500",
"testERC20Transfer_ERC4337MinimalAccount_ERC20SelfPay": "199831",
"testERC20Transfer_IthacaAccount": "128059",
"testERC20Transfer_IthacaAccountWithSpendLimits": "193602",
"testERC20Transfer_IthacaAccount_AppSponsor": "138595",
"testERC20Transfer_IthacaAccount_AppSponsor_ERC20": "143884",
"testERC20Transfer_IthacaAccount_ERC20SelfPay": "128548",
"testERC20Transfer_IthacaAccount": "128100",
"testERC20Transfer_IthacaAccountWithSpendLimits": "193589",
"testERC20Transfer_IthacaAccount_AppSponsor": "138636",
"testERC20Transfer_IthacaAccount_AppSponsor_ERC20": "143937",
"testERC20Transfer_IthacaAccount_ERC20SelfPay": "128589",
"testERC20Transfer_Safe4337": "197561",
"testERC20Transfer_Safe4337_AppSponsor": "191725",
"testERC20Transfer_Safe4337_ERC20SelfPay": "221464",
Expand All @@ -29,25 +29,25 @@
"testERC20Transfer_ZerodevKernel_ERC20SelfPay": "235489",
"testERC20Transfer_batch100_AlchemyModularAccount": "10109066",
"testERC20Transfer_batch100_AlchemyModularAccount_ERC20SelfPay": "11609298",
"testERC20Transfer_batch100_IthacaAccount": "7531912",
"testERC20Transfer_batch100_IthacaAccount_AppSponsor": "8140216",
"testERC20Transfer_batch100_IthacaAccount_AppSponsor_ERC20": "7966120",
"testERC20Transfer_batch100_IthacaAccount_ERC20SelfPay": "7353064",
"testERC20Transfer_batch100_IthacaAccount": "7535892",
"testERC20Transfer_batch100_IthacaAccount_AppSponsor": "8144196",
"testERC20Transfer_batch100_IthacaAccount_AppSponsor_ERC20": "7970208",
"testERC20Transfer_batch100_IthacaAccount_ERC20SelfPay": "7357152",
"testERC20Transfer_batch100_ZerodevKernel": "12631318",
"testERC20Transfer_batch100_ZerodevKernel_ERC20SelfPay": "14149937",
"testNativeTransfer_AlchemyModularAccount": "180829",
"testNativeTransfer_CoinbaseSmartWallet": "178916",
"testNativeTransfer_IthacaAccount": "129415",
"testNativeTransfer_IthacaAccount_AppSponsor": "139982",
"testNativeTransfer_IthacaAccount_ERC20SelfPay": "137204",
"testNativeTransfer_IthacaAccount": "129456",
"testNativeTransfer_IthacaAccount_AppSponsor": "140023",
"testNativeTransfer_IthacaAccount_ERC20SelfPay": "137245",
"testNativeTransfer_Safe4337": "198595",
"testNativeTransfer_ZerodevKernel": "208635",
"testUniswapV2Swap_AlchemyModularAccount": "238647",
"testUniswapV2Swap_CoinbaseSmartWallet": "237451",
"testUniswapV2Swap_ERC4337MinimalAccount": "230691",
"testUniswapV2Swap_IthacaAccount": "187179",
"testUniswapV2Swap_IthacaAccount_AppSponsor": "197691",
"testUniswapV2Swap_IthacaAccount_ERC20SelfPay": "192480",
"testUniswapV2Swap_IthacaAccount": "187244",
"testUniswapV2Swap_IthacaAccount_AppSponsor": "197744",
"testUniswapV2Swap_IthacaAccount_ERC20SelfPay": "192533",
"testUniswapV2Swap_Safe4337": "257333",
"testUniswapV2Swap_ZerodevKernel": "266367"
}
47 changes: 44 additions & 3 deletions src/IthacaAccount.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {LibNonce} from "./libraries/LibNonce.sol";
import {TokenTransferLib} from "./libraries/TokenTransferLib.sol";
import {LibTStack} from "./libraries/LibTStack.sol";
import {IIthacaAccount} from "./interfaces/IIthacaAccount.sol";
import {MerkleProofLib} from "solady/utils/MerkleProofLib.sol";

/// @title Account
/// @notice A account contract for EOAs with EIP7702.
Expand Down Expand Up @@ -490,9 +491,43 @@ contract IthacaAccount is IIthacaAccount, EIP712, GuardedExecutor {
return isMultichain ? _hashTypedDataSansChainId(structHash) : _hashTypedData(structHash);
}

/// @dev Verifies the merkle sig
/// - Note: Each leaf of the merkle tree should be a standard digest.
/// - The signature for using merkle verification is encoded as:
/// - bytes signature = abi.encode(bytes32[] proof, bytes32 root, bytes rootSig)
function _verifyMerkleSig(bytes32 digest, bytes calldata signature)
internal
view
returns (bool isValid, bytes32 keyHash)
{
bytes32[] calldata proof;
bytes32 root;
bytes calldata rootSig;

assembly ("memory-safe") {
Comment thread
Dargon789 marked this conversation as resolved.
let proofOffset := add(signature.offset, calldataload(signature.offset))
proof.length := calldataload(proofOffset)
proof.offset := add(proofOffset, 0x20)

root := calldataload(add(signature.offset, 0x20))

let rootSigOffset := add(signature.offset, calldataload(add(signature.offset, 0x40)))
rootSig.length := calldataload(rootSigOffset)
rootSig.offset := add(rootSigOffset, 0x20)
}

if (MerkleProofLib.verifyCalldata(proof, root, digest)) {
(isValid, keyHash) = unwrapAndValidateSignature(root, rootSig);

return (isValid, keyHash);
}

return (false, bytes32(0));
}

/// @dev Returns if the signature is valid, along with its `keyHash`.
/// The `signature` is a wrapped signature, given by
/// `abi.encodePacked(bytes(innerSignature), bytes32(keyHash), bool(prehash))`.
/// `abi.encode(bytes(innerSignature), bytes32(keyHash), bool(prehash), bool(merkle))`.
Comment thread
Dargon789 marked this conversation as resolved.
function unwrapAndValidateSignature(bytes32 digest, bytes calldata signature)
public
view
Comment thread
Dargon789 marked this conversation as resolved.
Expand All @@ -507,14 +542,20 @@ contract IthacaAccount is IIthacaAccount, EIP712, GuardedExecutor {
return (ECDSA.recoverCalldata(digest, signature) == address(this), 0);
}

bool merkle;
unchecked {
uint256 n = signature.length - 0x21;
uint256 n = signature.length - 0x22;
keyHash = LibBytes.loadCalldata(signature, n);
signature = LibBytes.truncatedCalldata(signature, n);
// Do the prehash if last byte is non-zero.
if (uint256(LibBytes.loadCalldata(signature, n + 1)) & 0xff != 0) {
digest = EfficientHashLib.sha2(digest); // `sha256(abi.encode(digest))`.
}
merkle = uint256(LibBytes.loadCalldata(signature, n + 2)) & 0xff != 0;
Comment thread
Dargon789 marked this conversation as resolved.
}

if (merkle) {
return _verifyMerkleSig(digest, signature);
}

Key memory key = getKey(keyHash);
Expand Down Expand Up @@ -755,6 +796,6 @@ contract IthacaAccount is IIthacaAccount, EIP712, GuardedExecutor {
returns (string memory name, string memory version)
{
name = "IthacaAccount";
version = "0.5.10";
version = "0.5.11";
}
}
Loading