From 2ecce316b8bad62c40f31a5ceeb500726d926d1c Mon Sep 17 00:00:00 2001 From: Tanishk Goyal Date: Wed, 24 Sep 2025 22:22:07 +0530 Subject: [PATCH 01/21] feat: add merkle sigs natively into the account --- snapshots/BenchmarkTest.json | 30 +++++++++--------- src/IthacaAccount.sol | 59 ++++++++++++++++++++++++++++++++++-- 2 files changed, 72 insertions(+), 17 deletions(-) diff --git a/snapshots/BenchmarkTest.json b/snapshots/BenchmarkTest.json index 2d5a899d..b32e01a9 100644 --- a/snapshots/BenchmarkTest.json +++ b/snapshots/BenchmarkTest.json @@ -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", @@ -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" } \ No newline at end of file diff --git a/src/IthacaAccount.sol b/src/IthacaAccount.sol index 45b2d6c8..cbe96ff3 100644 --- a/src/IthacaAccount.sol +++ b/src/IthacaAccount.sol @@ -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. @@ -490,9 +491,52 @@ contract IthacaAccount is IIthacaAccount, EIP712, GuardedExecutor { return isMultichain ? _hashTypedDataSansChainId(structHash) : _hashTypedData(structHash); } + /// @dev Verifies the merkle sig for the multi chain intents. + /// - Note: Each leaf of the merkle tree should be a standard intent digest, computed with chainId. + /// - Leaf intents do NOT need to have the multichain nonce prefix. + /// - The signature for multi chain intents 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") { + 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) + } + + console.logBytes32(root); + + console.log("Proof length: ", proof.length); + console.logBytes32(proof[0]); + + if (MerkleProofLib.verifyCalldata(proof, root, digest)) { + console.log("Entered here"); + (isValid, keyHash) = unwrapAndValidateSignature(root, rootSig); + + console.logBytes32(keyHash); + console.log(isValid); + 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))`. function unwrapAndValidateSignature(bytes32 digest, bytes calldata signature) public view @@ -507,14 +551,25 @@ 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) { + console.log("prehash"); digest = EfficientHashLib.sha2(digest); // `sha256(abi.encode(digest))`. } + merkle = uint256(LibBytes.loadCalldata(signature, n + 2)) & 0xff != 0; + } + + console.logBytes(signature); + + console.log("Reached here", merkle); + if (merkle) { + console.log("merkle"); + return _verifyMerkleSig(digest, signature); } Key memory key = getKey(keyHash); From 557774798309a3b79c070634f20d96b2a465c52b Mon Sep 17 00:00:00 2001 From: Tanishk Goyal Date: Wed, 24 Sep 2025 22:23:47 +0530 Subject: [PATCH 02/21] fix: tests --- src/IthacaAccount.sol | 20 +++---------------- test/Account.t.sol | 40 ++++++++++++++++++++++++++++++++++++-- test/Base.t.sol | 11 ++++++----- test/Orchestrator.t.sol | 5 +++-- test/SimulateExecute.t.sol | 3 ++- 5 files changed, 52 insertions(+), 27 deletions(-) diff --git a/src/IthacaAccount.sol b/src/IthacaAccount.sol index cbe96ff3..1dc7f18b 100644 --- a/src/IthacaAccount.sol +++ b/src/IthacaAccount.sol @@ -491,10 +491,9 @@ contract IthacaAccount is IIthacaAccount, EIP712, GuardedExecutor { return isMultichain ? _hashTypedDataSansChainId(structHash) : _hashTypedData(structHash); } - /// @dev Verifies the merkle sig for the multi chain intents. - /// - Note: Each leaf of the merkle tree should be a standard intent digest, computed with chainId. - /// - Leaf intents do NOT need to have the multichain nonce prefix. - /// - The signature for multi chain intents using merkle verification is encoded as: + /// @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 @@ -517,17 +516,9 @@ contract IthacaAccount is IIthacaAccount, EIP712, GuardedExecutor { rootSig.offset := add(rootSigOffset, 0x20) } - console.logBytes32(root); - - console.log("Proof length: ", proof.length); - console.logBytes32(proof[0]); - if (MerkleProofLib.verifyCalldata(proof, root, digest)) { - console.log("Entered here"); (isValid, keyHash) = unwrapAndValidateSignature(root, rootSig); - console.logBytes32(keyHash); - console.log(isValid); return (isValid, keyHash); } @@ -558,17 +549,12 @@ contract IthacaAccount is IIthacaAccount, EIP712, GuardedExecutor { signature = LibBytes.truncatedCalldata(signature, n); // Do the prehash if last byte is non-zero. if (uint256(LibBytes.loadCalldata(signature, n + 1)) & 0xff != 0) { - console.log("prehash"); digest = EfficientHashLib.sha2(digest); // `sha256(abi.encode(digest))`. } merkle = uint256(LibBytes.loadCalldata(signature, n + 2)) & 0xff != 0; } - console.logBytes(signature); - - console.log("Reached here", merkle); if (merkle) { - console.log("merkle"); return _verifyMerkleSig(digest, signature); } diff --git a/test/Account.t.sol b/test/Account.t.sol index e4b8310b..67e3fe50 100644 --- a/test/Account.t.sol +++ b/test/Account.t.sol @@ -6,6 +6,8 @@ import "./Base.t.sol"; import {MockSampleDelegateCallTarget} from "./utils/mocks/MockSampleDelegateCallTarget.sol"; import {LibEIP7702} from "solady/accounts/LibEIP7702.sol"; +import {Merkle} from "murky/Merkle.sol"; + contract AccountTest is BaseTest { struct _TestExecuteWithSignatureTemps { TargetFunctionPayload[] targetFunctionPayloads; @@ -68,6 +70,41 @@ contract AccountTest is BaseTest { } } + function testMerkleSignature(bytes32 randomDigest) public { + DelegatedEOA memory d = _randomEIP7702DelegatedEOA(); + PassKey memory k = _randomSecp256k1PassKey(); + + k.k.isSuperAdmin = true; + + vm.prank(d.eoa); + d.d.authorize(k.k); + + bytes32 actualDigest = keccak256("actualDigest"); + + Merkle merkle = new Merkle(); + + bytes32[] memory leaves = new bytes32[](2); + leaves[0] = actualDigest; + leaves[1] = randomDigest; + bytes32 root = merkle.getRoot(leaves); + + bytes32[] memory proof = merkle.getProof(leaves, 0); + + bytes memory rootSig = abi.encode(proof, root, _sig(k, root)); + bytes memory sig = abi.encodePacked(rootSig, bytes32(0), uint8(0), uint8(1)); + + (bool isValid, bytes32 keyHash) = d.d.unwrapAndValidateSignature(actualDigest, sig); + + assertEq(isValid, true); + assertEq(keyHash, k.keyHash); + + // Test some random digest + bytes32 randomDigest2 = keccak256("randomDigest2"); + (isValid, keyHash) = d.d.unwrapAndValidateSignature(randomDigest2, sig); + assertEq(isValid, false); + assertEq(keyHash, bytes32(0)); + } + function testSignatureCheckerApproval(bytes32) public { DelegatedEOA memory d = _randomEIP7702DelegatedEOA(); PassKey memory k = _randomSecp256k1PassKey(); @@ -93,8 +130,7 @@ contract AccountTest is BaseTest { bytes32 replaySafeDigest = keccak256(abi.encode(d.d.SIGN_TYPEHASH(), digest)); - (, string memory name, string memory version,, address verifyingContract,,) = - d.d.eip712Domain(); + (,,,, address verifyingContract,,) = d.d.eip712Domain(); bytes32 domain = keccak256( abi.encode( 0x035aff83d86937d35b32e04f0ddc6ff469290eef2f1b692d8a815c89404d4749, // DOMAIN_TYPEHASH with only verifyingContract diff --git a/test/Base.t.sol b/test/Base.t.sol index 1765a651..f9f91ac4 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -215,7 +215,7 @@ contract BaseTest is SoladyTest { { (bytes32 r, bytes32 s) = vm.signP256(privateKey, digest); s = P256.normalized(s); - return abi.encodePacked(abi.encode(r, s), keyHash, uint8(prehash ? 1 : 0)); + return abi.encodePacked(abi.encode(r, s), keyHash, uint8(prehash ? 1 : 0), uint8(0)); } function _secp256k1Sig(uint256 privateKey, bytes32 keyHash, bytes32 digest) @@ -232,7 +232,8 @@ contract BaseTest is SoladyTest { returns (bytes memory) { (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest); - return abi.encodePacked(abi.encodePacked(r, s, v), keyHash, uint8(prehash ? 1 : 0)); + return + abi.encodePacked(abi.encodePacked(r, s, v), keyHash, uint8(prehash ? 1 : 0), uint8(0)); } function _multiSig(MultiSigKey memory k, bytes32 keyHash, bool preHash, bytes32 digest) @@ -245,7 +246,7 @@ contract BaseTest is SoladyTest { signatures[i] = _sig(k.owners[i], digest); } - return abi.encodePacked(abi.encode(signatures), keyHash, uint8(preHash ? 1 : 0)); + return abi.encodePacked(abi.encode(signatures), keyHash, uint8(preHash ? 1 : 0), uint8(0)); } function _estimateGasForEOAKey(Orchestrator.Intent memory i) @@ -277,7 +278,7 @@ contract BaseTest is SoladyTest { { (uint8 v, bytes32 r, bytes32 s) = vm.sign(uint128(_randomUniform()), bytes32(_randomUniform())); - i.signature = abi.encodePacked(abi.encodePacked(r, s, v), keyHash, uint8(0)); + i.signature = abi.encodePacked(abi.encodePacked(r, s, v), keyHash, uint8(0), uint8(0)); return _estimateGas(i); } @@ -285,7 +286,7 @@ contract BaseTest is SoladyTest { internal returns (uint256 gExecute, uint256 gCombined, uint256 gUsed) { - i.signature = abi.encodePacked(keccak256("a"), keccak256("b"), keyHash, uint8(0)); + i.signature = abi.encodePacked(keccak256("a"), keccak256("b"), keyHash, uint8(0), uint8(0)); return _estimateGas(i); } diff --git a/test/Orchestrator.t.sol b/test/Orchestrator.t.sol index c36a3248..c5cc3cc1 100644 --- a/test/Orchestrator.t.sol +++ b/test/Orchestrator.t.sol @@ -924,8 +924,9 @@ contract OrchestratorTest is BaseTest { if (_randomChance(16)) { u.combinedGas += 10_000; // Fill with some junk signature, but with the session `keyHash`. - u.signature = - abi.encodePacked(keccak256("a"), keccak256("b"), kSession.keyHash, uint8(0)); + u.signature = abi.encodePacked( + keccak256("a"), keccak256("b"), kSession.keyHash, uint8(0), uint8(0) + ); (t.gExecute, t.gCombined, t.gUsed) = _estimateGas(u); diff --git a/test/SimulateExecute.t.sol b/test/SimulateExecute.t.sol index 681266f7..aa3261cd 100644 --- a/test/SimulateExecute.t.sol +++ b/test/SimulateExecute.t.sol @@ -300,7 +300,8 @@ contract SimulateExecuteTest is BaseTest { // it needs to add the variance for non-precompile P256 verification. // We need the `keyHash` in the signature so that the simulation is able // to hit all the gas for the GuardedExecutor stuff for the `keyHash`. - i.signature = abi.encodePacked(keccak256("a"), keccak256("b"), k.keyHash, uint8(0)); + i.signature = + abi.encodePacked(keccak256("a"), keccak256("b"), k.keyHash, uint8(0), uint8(0)); uint256 snapshot = vm.snapshotState(); vm.deal(_ORIGIN_ADDRESS, type(uint192).max); From 995a3e17a01c2d9e12bcdbc9384cfdd4f00b1d4c Mon Sep 17 00:00:00 2001 From: Tanishk Goyal Date: Wed, 24 Sep 2025 22:29:40 +0530 Subject: [PATCH 03/21] test: add more sophisticated fuzz test --- test/Account.t.sol | 69 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 20 deletions(-) diff --git a/test/Account.t.sol b/test/Account.t.sol index 67e3fe50..21c7c36e 100644 --- a/test/Account.t.sol +++ b/test/Account.t.sol @@ -70,39 +70,68 @@ contract AccountTest is BaseTest { } } - function testMerkleSignature(bytes32 randomDigest) public { + function testMerkleSignature(uint256 seed) public { DelegatedEOA memory d = _randomEIP7702DelegatedEOA(); PassKey memory k = _randomSecp256k1PassKey(); - k.k.isSuperAdmin = true; vm.prank(d.eoa); d.d.authorize(k.k); - bytes32 actualDigest = keccak256("actualDigest"); - - Merkle merkle = new Merkle(); + // Fuzz number of leaves (2 to 256) + uint256 numLeaves = bound(seed, 2, 256); + bytes32[] memory leaves = new bytes32[](numLeaves); - bytes32[] memory leaves = new bytes32[](2); - leaves[0] = actualDigest; - leaves[1] = randomDigest; - bytes32 root = merkle.getRoot(leaves); + // Generate random leaves + for (uint256 i = 0; i < numLeaves; i++) { + leaves[i] = keccak256(abi.encodePacked("leaf", i, seed)); + } - bytes32[] memory proof = merkle.getProof(leaves, 0); + // Pick a random valid index + uint256 validIndex = seed % numLeaves; + bytes32 validDigest = leaves[validIndex]; - bytes memory rootSig = abi.encode(proof, root, _sig(k, root)); - bytes memory sig = abi.encodePacked(rootSig, bytes32(0), uint8(0), uint8(1)); + Merkle merkle = new Merkle(); + bytes32 root = merkle.getRoot(leaves); + bytes32[] memory proof = merkle.getProof(leaves, validIndex); - (bool isValid, bytes32 keyHash) = d.d.unwrapAndValidateSignature(actualDigest, sig); + // Test valid merkle proof + { + bytes memory rootSig = abi.encode(proof, root, _sig(k, root)); + bytes memory sig = abi.encodePacked(rootSig, bytes32(0), uint8(0), uint8(1)); + + (bool isValid, bytes32 keyHash) = d.d.unwrapAndValidateSignature(validDigest, sig); + assertEq(isValid, true); + assertEq(keyHash, k.keyHash); + + // Test invalid digest not in tree + bytes32 invalidDigest = keccak256(abi.encodePacked("not_in_tree", seed)); + (isValid, keyHash) = d.d.unwrapAndValidateSignature(invalidDigest, sig); + assertEq(isValid, false); + assertEq(keyHash, bytes32(0)); + } - assertEq(isValid, true); - assertEq(keyHash, k.keyHash); + // Test tampered proof (only if proof has elements to tamper) + if (proof.length > 0) { + bytes32[] memory tamperedProof = new bytes32[](proof.length); + for (uint256 i = 0; i < proof.length; i++) { + tamperedProof[i] = i == 0 ? bytes32(uint256(proof[i]) ^ 1) : proof[i]; + } + bytes memory tamperedRootSig = abi.encode(tamperedProof, root, _sig(k, root)); + bytes memory tamperedSig = + abi.encodePacked(tamperedRootSig, bytes32(0), uint8(0), uint8(1)); + (bool isValid,) = d.d.unwrapAndValidateSignature(validDigest, tamperedSig); + assertEq(isValid, false); + } - // Test some random digest - bytes32 randomDigest2 = keccak256("randomDigest2"); - (isValid, keyHash) = d.d.unwrapAndValidateSignature(randomDigest2, sig); - assertEq(isValid, false); - assertEq(keyHash, bytes32(0)); + // Test wrong root (tampered root should fail verification) + { + bytes32 wrongRoot = bytes32(uint256(root) ^ 1); + bytes memory wrongRootSig = abi.encode(proof, wrongRoot, _sig(k, wrongRoot)); + bytes memory wrongSig = abi.encodePacked(wrongRootSig, bytes32(0), uint8(0), uint8(1)); + (bool isValid,) = d.d.unwrapAndValidateSignature(validDigest, wrongSig); + assertEq(isValid, false); + } } function testSignatureCheckerApproval(bytes32) public { From 4918a12d97acfad5294fbbc151c7fa12c8c13b26 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 24 Sep 2025 17:05:28 +0000 Subject: [PATCH 04/21] chore: bump contract versions due to bytecode changes - Contracts updated: IthacaAccount --- src/IthacaAccount.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/IthacaAccount.sol b/src/IthacaAccount.sol index 1dc7f18b..a8ffdbca 100644 --- a/src/IthacaAccount.sol +++ b/src/IthacaAccount.sol @@ -796,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"; } } From 68f4e3a3415ac4fe31324ea7687043894ea69e9f Mon Sep 17 00:00:00 2001 From: Dargon789 <64915515+Dargon789@users.noreply.github.com> Date: Wed, 19 Nov 2025 20:04:56 +0700 Subject: [PATCH 05/21] Add .circleci/config.yml (#1) Add CircleCI configuration file to set up a basic pipeline with a say-hello job and workflow CI: Add .circleci/config.yml to define a say-hello job that checks out the code and prints a greeting using the cimg/base Docker image Add a workflow to orchestrate the say-hello job under the CircleCI 2.1 engine --- .circleci/config.yml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .circleci/config.yml diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 00000000..bb68b14a --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,31 @@ +# Use the latest 2.1 version of CircleCI pipeline process engine. +# See: https://circleci.com/docs/reference/configuration-reference +version: 2.1 + +# Define a job to be invoked later in a workflow. +# See: https://circleci.com/docs/guides/orchestrate/jobs-steps/#jobs-overview & https://circleci.com/docs/reference/configuration-reference/#jobs +jobs: + say-hello: + # Specify the execution environment. You can specify an image from Docker Hub or use one of our convenience images from CircleCI's Developer Hub. + # See: https://circleci.com/docs/guides/execution-managed/executor-intro/ & https://circleci.com/docs/reference/configuration-reference/#executor-job + docker: + # Specify the version you desire here + # See: https://circleci.com/developer/images/image/cimg/base + - image: cimg/base:current + + # Add steps to the job + # See: https://circleci.com/docs/guides/orchestrate/jobs-steps/#steps-overview & https://circleci.com/docs/reference/configuration-reference/#steps + steps: + # Checkout the code as the first step. + - checkout + - run: + name: "Say hello" + command: "echo Hello, World!" + +# Orchestrate jobs using workflows +# See: https://circleci.com/docs/guides/orchestrate/workflows/ & https://circleci.com/docs/reference/configuration-reference/#workflows +workflows: + say-hello-workflow: # This is the name of the workflow, feel free to change it to better match your workflow. + # Inside the workflow, you define the jobs you want to run. + jobs: + - say-hello \ No newline at end of file From 2f484ce9c031409dbed91c1f614af40e9c459385 Mon Sep 17 00:00:00 2001 From: Dargon789 <64915515+Dargon789@users.noreply.github.com> Date: Wed, 19 Nov 2025 20:41:44 +0700 Subject: [PATCH 06/21] Update ci.yaml Signed-off-by: Dargon789 <64915515+Dargon789@users.noreply.github.com> --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 6915c959..4f705020 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -33,7 +33,7 @@ jobs: UPGRADE_TEST_OLD_PROXY: ${{ secrets.UPGRADE_TEST_OLD_PROXY }} UPGRADE_TEST_OLD_VERSION: ${{ secrets.UPGRADE_TEST_OLD_VERSION }} run: | - forge test -vvv + forge test --rerun -vvvvv - name: Format contracts and generate snapshots if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository From cef256e2a32296ea45b3fc0484c3ccdd70ac35ca Mon Sep 17 00:00:00 2001 From: Dargon789 <64915515+Dargon789@users.noreply.github.com> Date: Wed, 19 Nov 2025 20:54:18 +0700 Subject: [PATCH 07/21] Update ci.yaml (#2) CI: Update Forge test command to use --rerun and increase verbosity to -vvvvv Signed-off-by: Dargon789 <64915515+Dargon789@users.noreply.github.com> --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 6915c959..4f705020 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -33,7 +33,7 @@ jobs: UPGRADE_TEST_OLD_PROXY: ${{ secrets.UPGRADE_TEST_OLD_PROXY }} UPGRADE_TEST_OLD_VERSION: ${{ secrets.UPGRADE_TEST_OLD_VERSION }} run: | - forge test -vvv + forge test --rerun -vvvvv - name: Format contracts and generate snapshots if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository From bcd85272adebd7a41c04fb3a1453dcfbc60b45a6 Mon Sep 17 00:00:00 2001 From: Dargon789 <64915515+Dargon789@users.noreply.github.com> Date: Thu, 20 Nov 2025 02:23:30 +0700 Subject: [PATCH 08/21] Update ci.yaml (#4) Enhance the CI test step to automatically rerun failed tests and increase verbosity in Forge. CI: Enable the --rerun flag for Forge tests to retry failures automatically Increase Forge test verbosity from -vvv to -vvvvv Signed-off-by: Dargon789 <64915515+Dargon789@users.noreply.github.com> From 01aafc57598cdcf2dc25569ba24cd0b150d95c20 Mon Sep 17 00:00:00 2001 From: Dargon789 <64915515+Dargon789@users.noreply.github.com> Date: Thu, 20 Nov 2025 13:47:48 +0700 Subject: [PATCH 09/21] Update ci.yaml (#5) Change Forge test invocation from "forge test --rerun -vvvvv" to "forge test -vvv" Signed-off-by: Dargon789 <64915515+Dargon789@users.noreply.github.com> --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 4f705020..6915c959 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -33,7 +33,7 @@ jobs: UPGRADE_TEST_OLD_PROXY: ${{ secrets.UPGRADE_TEST_OLD_PROXY }} UPGRADE_TEST_OLD_VERSION: ${{ secrets.UPGRADE_TEST_OLD_VERSION }} run: | - forge test --rerun -vvvvv + forge test -vvv - name: Format contracts and generate snapshots if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository From 21aa94248bd541d55366d5164d97ec61780f8f0b Mon Sep 17 00:00:00 2001 From: Dargon789 <64915515+Dargon789@users.noreply.github.com> Date: Thu, 20 Nov 2025 13:56:48 +0700 Subject: [PATCH 10/21] Update ci.yaml Signed-off-by: Dargon789 <64915515+Dargon789@users.noreply.github.com> --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 6915c959..6de4b9e5 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -33,7 +33,7 @@ jobs: UPGRADE_TEST_OLD_PROXY: ${{ secrets.UPGRADE_TEST_OLD_PROXY }} UPGRADE_TEST_OLD_VERSION: ${{ secrets.UPGRADE_TEST_OLD_VERSION }} run: | - forge test -vvv + forge test --no-match-contract UpgradeTests - name: Format contracts and generate snapshots if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository From a317ddb944a1f5ed7294092790902da6b255f73f Mon Sep 17 00:00:00 2001 From: Dargon789 <64915515+Dargon789@users.noreply.github.com> Date: Sat, 20 Dec 2025 20:50:05 +0700 Subject: [PATCH 11/21] Create CNAME --- CNAME | 1 + 1 file changed, 1 insertion(+) create mode 100644 CNAME diff --git a/CNAME b/CNAME new file mode 100644 index 00000000..a37c284a --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +legion-rouge.vercel.app \ No newline at end of file From 28ff37f5bacd9d0a4a56db643d72d0e33cf13c87 Mon Sep 17 00:00:00 2001 From: Dargon789 <64915515+Dargon789@users.noreply.github.com> Date: Sun, 21 Dec 2025 20:37:13 +0700 Subject: [PATCH 12/21] Revert "Merge branch 'master'" This reverts commit 6c02fbff6486bb206c08af83d948830ace042353, reversing changes made to a317ddb944a1f5ed7294092790902da6b255f73f. --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 4f705020..6de4b9e5 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -33,7 +33,7 @@ jobs: UPGRADE_TEST_OLD_PROXY: ${{ secrets.UPGRADE_TEST_OLD_PROXY }} UPGRADE_TEST_OLD_VERSION: ${{ secrets.UPGRADE_TEST_OLD_VERSION }} run: | - forge test --rerun -vvvvv + forge test --no-match-contract UpgradeTests - name: Format contracts and generate snapshots if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository From 0d5c95739c7711c10b8bdbf3a6af9c3c1a8c2864 Mon Sep 17 00:00:00 2001 From: Dargon789 <64915515+Dargon789@users.noreply.github.com> Date: Sun, 21 Dec 2025 21:38:32 +0700 Subject: [PATCH 13/21] Create CNAME (#9) * Update ci.yaml (#2) CI: Update Forge test command to use --rerun and increase verbosity to -vvvvv Signed-off-by: Dargon789 <64915515+Dargon789@users.noreply.github.com> * Update ci.yaml (#4) Enhance the CI test step to automatically rerun failed tests and increase verbosity in Forge. CI: Enable the --rerun flag for Forge tests to retry failures automatically Increase Forge test verbosity from -vvv to -vvvvv Signed-off-by: Dargon789 <64915515+Dargon789@users.noreply.github.com> * Update ci.yaml (#5) Change Forge test invocation from "forge test --rerun -vvvvv" to "forge test -vvv" Signed-off-by: Dargon789 <64915515+Dargon789@users.noreply.github.com> * Update ci.yaml Signed-off-by: Dargon789 <64915515+Dargon789@users.noreply.github.com> * Create CNAME * Revert "Merge branch 'master'" This reverts commit 6c02fbff6486bb206c08af83d948830ace042353, reversing changes made to a317ddb944a1f5ed7294092790902da6b255f73f. --------- Signed-off-by: Dargon789 <64915515+Dargon789@users.noreply.github.com> --- .github/workflows/ci.yaml | 2 +- CNAME | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 CNAME diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 4f705020..6de4b9e5 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -33,7 +33,7 @@ jobs: UPGRADE_TEST_OLD_PROXY: ${{ secrets.UPGRADE_TEST_OLD_PROXY }} UPGRADE_TEST_OLD_VERSION: ${{ secrets.UPGRADE_TEST_OLD_VERSION }} run: | - forge test --rerun -vvvvv + forge test --no-match-contract UpgradeTests - name: Format contracts and generate snapshots if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository diff --git a/CNAME b/CNAME new file mode 100644 index 00000000..a37c284a --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +legion-rouge.vercel.app \ No newline at end of file From 28d5bc8fa850920dff2f47f900af90792ab0550e Mon Sep 17 00:00:00 2001 From: Dargon789 <64915515+Dargon789@users.noreply.github.com> Date: Tue, 10 Feb 2026 11:06:14 +0000 Subject: [PATCH 14/21] Delete .circleci directory (#27) Signed-off-by: Dargon789 <64915515+Dargon789@users.noreply.github.com> --- .circleci/config.yml | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100644 .circleci/config.yml diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index bb68b14a..00000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,31 +0,0 @@ -# Use the latest 2.1 version of CircleCI pipeline process engine. -# See: https://circleci.com/docs/reference/configuration-reference -version: 2.1 - -# Define a job to be invoked later in a workflow. -# See: https://circleci.com/docs/guides/orchestrate/jobs-steps/#jobs-overview & https://circleci.com/docs/reference/configuration-reference/#jobs -jobs: - say-hello: - # Specify the execution environment. You can specify an image from Docker Hub or use one of our convenience images from CircleCI's Developer Hub. - # See: https://circleci.com/docs/guides/execution-managed/executor-intro/ & https://circleci.com/docs/reference/configuration-reference/#executor-job - docker: - # Specify the version you desire here - # See: https://circleci.com/developer/images/image/cimg/base - - image: cimg/base:current - - # Add steps to the job - # See: https://circleci.com/docs/guides/orchestrate/jobs-steps/#steps-overview & https://circleci.com/docs/reference/configuration-reference/#steps - steps: - # Checkout the code as the first step. - - checkout - - run: - name: "Say hello" - command: "echo Hello, World!" - -# Orchestrate jobs using workflows -# See: https://circleci.com/docs/guides/orchestrate/workflows/ & https://circleci.com/docs/reference/configuration-reference/#workflows -workflows: - say-hello-workflow: # This is the name of the workflow, feel free to change it to better match your workflow. - # Inside the workflow, you define the jobs you want to run. - jobs: - - say-hello \ No newline at end of file From e730f4120ad57055b4abed36f60175adfb08c402 Mon Sep 17 00:00:00 2001 From: googleworkspace-bot Date: Fri, 13 Mar 2026 15:56:45 +0700 Subject: [PATCH 15/21] pre-commit --- .husky/pre-commit | 0 deploy/execute_config.sh | 0 deploy/verify_config.sh | 0 lib/forge-std | 2 +- prep/check-bytecode-changes.js | 0 5 files changed, 1 insertion(+), 1 deletion(-) mode change 100755 => 100644 .husky/pre-commit mode change 100755 => 100644 deploy/execute_config.sh mode change 100755 => 100644 deploy/verify_config.sh mode change 100755 => 100644 prep/check-bytecode-changes.js diff --git a/.husky/pre-commit b/.husky/pre-commit old mode 100755 new mode 100644 diff --git a/deploy/execute_config.sh b/deploy/execute_config.sh old mode 100755 new mode 100644 diff --git a/deploy/verify_config.sh b/deploy/verify_config.sh old mode 100755 new mode 100644 diff --git a/lib/forge-std b/lib/forge-std index c2cf7017..0844d7e1 160000 --- a/lib/forge-std +++ b/lib/forge-std @@ -1 +1 @@ -Subproject commit c2cf7017d27c1d20e74ace4dacb6c5ce4bbbe899 +Subproject commit 0844d7e1fc5e60d77b68e469bff60265f236c398 diff --git a/prep/check-bytecode-changes.js b/prep/check-bytecode-changes.js old mode 100755 new mode 100644 From 42416668eb6450d9fb45f00e74e0921eaa618a91 Mon Sep 17 00:00:00 2001 From: googleworkspace-bot Date: Fri, 13 Mar 2026 16:20:26 +0700 Subject: [PATCH 16/21] deploy execute_config.sh --- deploy/execute_config.sh | 0 deploy/verify_config.sh | 0 prep/check-bytecode-changes.js | 0 3 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 deploy/execute_config.sh mode change 100755 => 100644 deploy/verify_config.sh mode change 100755 => 100644 prep/check-bytecode-changes.js diff --git a/deploy/execute_config.sh b/deploy/execute_config.sh old mode 100755 new mode 100644 diff --git a/deploy/verify_config.sh b/deploy/verify_config.sh old mode 100755 new mode 100644 diff --git a/prep/check-bytecode-changes.js b/prep/check-bytecode-changes.js old mode 100755 new mode 100644 From cbd478bfdb4285a3792129841643941141a5ae1f Mon Sep 17 00:00:00 2001 From: googleworkspace-bot Date: Fri, 13 Mar 2026 16:23:26 +0700 Subject: [PATCH 17/21] Update forge-std --- lib/forge-std | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/forge-std b/lib/forge-std index 0844d7e1..c2cf7017 160000 --- a/lib/forge-std +++ b/lib/forge-std @@ -1 +1 @@ -Subproject commit 0844d7e1fc5e60d77b68e469bff60265f236c398 +Subproject commit c2cf7017d27c1d20e74ace4dacb6c5ce4bbbe899 From 751cf29d00bf14d364736de81b17e54bea2c1fe7 Mon Sep 17 00:00:00 2001 From: googleworkspace-bot Date: Sat, 14 Mar 2026 15:04:50 +0700 Subject: [PATCH 18/21] test: add tests for getContextKeyHash in Account.t.sol (#412) --- deploy/execute_config.sh | 0 deploy/verify_config.sh | 0 prep/check-bytecode-changes.js | 0 3 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 deploy/execute_config.sh mode change 100755 => 100644 deploy/verify_config.sh mode change 100755 => 100644 prep/check-bytecode-changes.js diff --git a/deploy/execute_config.sh b/deploy/execute_config.sh old mode 100755 new mode 100644 diff --git a/deploy/verify_config.sh b/deploy/verify_config.sh old mode 100755 new mode 100644 diff --git a/prep/check-bytecode-changes.js b/prep/check-bytecode-changes.js old mode 100755 new mode 100644 From ab9e8839428e1a9f047cb65d708ae02e270b23e9 Mon Sep 17 00:00:00 2001 From: googleworkspace-bot Date: Fri, 10 Apr 2026 07:28:05 +0700 Subject: [PATCH 19/21] Normalize file modes and update forge-std submodule MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove executable bit from deploy/execute_config.sh, deploy/verify_config.sh, and prep/check-bytecode-changes.js (mode 100755 → 100644). Update lib/forge-std submodule from commit c2cf7017d27c1d20e74ace4dacb6c5ce4bbbe899 to 07853315f998f94dc724e464b1bab1270888ee64. No other content changes. --- deploy/execute_config.sh | 0 deploy/verify_config.sh | 0 lib/forge-std | 2 +- prep/check-bytecode-changes.js | 0 4 files changed, 1 insertion(+), 1 deletion(-) mode change 100755 => 100644 deploy/execute_config.sh mode change 100755 => 100644 deploy/verify_config.sh mode change 100755 => 100644 prep/check-bytecode-changes.js diff --git a/deploy/execute_config.sh b/deploy/execute_config.sh old mode 100755 new mode 100644 diff --git a/deploy/verify_config.sh b/deploy/verify_config.sh old mode 100755 new mode 100644 diff --git a/lib/forge-std b/lib/forge-std index c2cf7017..07853315 160000 --- a/lib/forge-std +++ b/lib/forge-std @@ -1 +1 @@ -Subproject commit c2cf7017d27c1d20e74ace4dacb6c5ce4bbbe899 +Subproject commit 07853315f998f94dc724e464b1bab1270888ee64 diff --git a/prep/check-bytecode-changes.js b/prep/check-bytecode-changes.js old mode 100755 new mode 100644 From 36249c78e5e0dcb50bafa0a262e3c0b1cffba637 Mon Sep 17 00:00:00 2001 From: googleworkspace-bot Date: Sat, 11 Apr 2026 18:01:29 +0700 Subject: [PATCH 20/21] Update LayerZero-v2 --- lib/LayerZero-v2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/LayerZero-v2 b/lib/LayerZero-v2 index 88428755..ab9b0834 160000 --- a/lib/LayerZero-v2 +++ b/lib/LayerZero-v2 @@ -1 +1 @@ -Subproject commit 88428755be6caa71cb1d2926141d73c8989296b5 +Subproject commit ab9b083410b9359285a5756807e1b6145d4711a7 From d54a37b96fbf4cfc1815c7bdf385cbc01fec2aff Mon Sep 17 00:00:00 2001 From: googleworkspace-bot Date: Sat, 11 Apr 2026 19:03:24 +0700 Subject: [PATCH 21/21] Update LayerZero-v2 --- lib/LayerZero-v2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/LayerZero-v2 b/lib/LayerZero-v2 index 88428755..ab9b0834 160000 --- a/lib/LayerZero-v2 +++ b/lib/LayerZero-v2 @@ -1 +1 @@ -Subproject commit 88428755be6caa71cb1d2926141d73c8989296b5 +Subproject commit ab9b083410b9359285a5756807e1b6145d4711a7