From a32ef83792ca0670ed826b49628d1a83227d0ce8 Mon Sep 17 00:00:00 2001 From: Kogaroshi <25688223+Kogaroshi@users.noreply.github.com> Date: Tue, 17 Feb 2026 14:05:52 +0100 Subject: [PATCH 1/3] rft : add create1 helpers in tests --- tests/Base.t.sol | 1 + tests/Create1Utils.sol | 23 +++++++++++++++++++++ tests/DeployUtils.sol | 32 +++++++++++++++++++---------- tests/mocks/DeployWrapper.sol | 27 +++++++++++++++++++++++- tests/unit/Hub/Hub.Config.t.sol | 2 +- tests/unit/Spoke/Spoke.Config.t.sol | 6 +++--- 6 files changed, 75 insertions(+), 16 deletions(-) create mode 100644 tests/Create1Utils.sol diff --git a/tests/Base.t.sol b/tests/Base.t.sol index d441c983f..6859fc97b 100644 --- a/tests/Base.t.sol +++ b/tests/Base.t.sol @@ -82,6 +82,7 @@ import {SignatureGateway, ISignatureGateway} from 'src/position-manager/Signatur // test import {Constants} from 'tests/Constants.sol'; import {DeployUtils} from 'tests/DeployUtils.sol'; +import {Create1Utils} from 'tests/Create1Utils.sol'; import {Utils} from 'tests/Utils.sol'; // mocks diff --git a/tests/Create1Utils.sol b/tests/Create1Utils.sol new file mode 100644 index 000000000..e0bc6d0b2 --- /dev/null +++ b/tests/Create1Utils.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: UNLICENSED +// Copyright (c) 2025 Aave Labs +pragma solidity ^0.8.0; + +import {Vm} from 'forge-std/Vm.sol'; + +library Create1Utils { + error Create1DeploymentFailed(); + + Vm internal constant vm = Vm(address(uint160(uint256(keccak256('hevm cheat code'))))); + + function create1Deploy(bytes memory bytecode) internal returns (address addr) { + /// @solidity memory-safe-assembly + assembly { + addr := create(0, add(bytecode, 0x20), mload(bytecode)) + } + require(addr != address(0), Create1DeploymentFailed()); + } + + function computeCreate1Address(address deployer, uint256 nonce) internal pure returns (address) { + return vm.computeCreateAddress(deployer, nonce); + } +} diff --git a/tests/DeployUtils.sol b/tests/DeployUtils.sol index e928effd6..ac1b60d53 100644 --- a/tests/DeployUtils.sol +++ b/tests/DeployUtils.sol @@ -7,6 +7,7 @@ import {TransparentUpgradeableProxy} from 'src/dependencies/openzeppelin/Transpa import {IHub} from 'src/hub/interfaces/IHub.sol'; import {ISpoke} from 'src/spoke/interfaces/ISpoke.sol'; import {ISpokeInstance} from 'tests/mocks/ISpokeInstance.sol'; +import {Create1Utils} from 'tests/Create1Utils.sol'; import {Create2Utils} from 'tests/Create2Utils.sol'; library DeployUtils { @@ -16,7 +17,10 @@ library DeployUtils { address oracle, uint16 maxUserReservesLimit ) internal returns (ISpokeInstance) { - return deploySpokeImplementation(oracle, maxUserReservesLimit, ''); + return + ISpokeInstance( + Create1Utils.create1Deploy(_getSpokeInstanceInitCode(oracle, maxUserReservesLimit)) + ); } function deploySpokeImplementation( @@ -40,18 +44,28 @@ library DeployUtils { return ISpoke( proxify( - address(deploySpokeImplementation(oracle, maxUserReservesLimit, '')), + address(deploySpokeImplementation(oracle, maxUserReservesLimit)), proxyAdminOwner, initData ) ); } - function getDeterministicSpokeInstanceAddress( + function deploySpoke( address oracle, - uint16 maxUserReservesLimit - ) internal returns (address) { - return getDeterministicSpokeInstanceAddress(oracle, maxUserReservesLimit, ''); + uint16 maxUserReservesLimit, + address proxyAdminOwner, + bytes32 salt, + bytes memory initData + ) internal returns (ISpoke) { + return + ISpoke( + proxify( + address(deploySpokeImplementation(oracle, maxUserReservesLimit, salt)), + proxyAdminOwner, + initData + ) + ); } function getDeterministicSpokeInstanceAddress( @@ -66,7 +80,7 @@ library DeployUtils { } function deployHub(address authority) internal returns (IHub) { - return deployHub(authority, ''); + return IHub(Create1Utils.create1Deploy(_getHubInitCode(authority))); } function deployHub(address authority, bytes32 salt) internal returns (IHub hub) { @@ -74,10 +88,6 @@ library DeployUtils { return IHub(Create2Utils.create2Deploy(salt, _getHubInitCode(authority))); } - function getDeterministicHubAddress(address authority) internal returns (address) { - return getDeterministicHubAddress(authority, ''); - } - function getDeterministicHubAddress(address authority, bytes32 salt) internal returns (address) { bytes32 initCodeHash = keccak256(_getHubInitCode(authority)); diff --git a/tests/mocks/DeployWrapper.sol b/tests/mocks/DeployWrapper.sol index 49b3b673b..d48001fe6 100644 --- a/tests/mocks/DeployWrapper.sol +++ b/tests/mocks/DeployWrapper.sol @@ -9,7 +9,15 @@ contract DeployWrapper { address oracle, uint16 maxUserReservesLimit ) external returns (address) { - return address(DeployUtils.deploySpokeImplementation(oracle, maxUserReservesLimit, '')); + return address(DeployUtils.deploySpokeImplementation(oracle, maxUserReservesLimit)); + } + + function deploySpokeImplementation( + address oracle, + uint16 maxUserReservesLimit, + bytes32 salt + ) external returns (address) { + return address(DeployUtils.deploySpokeImplementation(oracle, maxUserReservesLimit, salt)); } function deploySpoke( @@ -22,7 +30,24 @@ contract DeployWrapper { address(DeployUtils.deploySpoke(oracle, maxUserReservesLimit, proxyAdminOwner, initData)); } + function deploySpoke( + address oracle, + uint16 maxUserReservesLimit, + address proxyAdminOwner, + bytes32 salt, + bytes calldata initData + ) external returns (address) { + return + address( + DeployUtils.deploySpoke(oracle, maxUserReservesLimit, proxyAdminOwner, salt, initData) + ); + } + function deployHub(address authority) external returns (address) { return address(DeployUtils.deployHub(authority)); } + + function deployHub(address authority, bytes32 salt) external returns (address) { + return address(DeployUtils.deployHub(authority, salt)); + } } diff --git a/tests/unit/Hub/Hub.Config.t.sol b/tests/unit/Hub/Hub.Config.t.sol index 42cfde53b..9ad04a52c 100644 --- a/tests/unit/Hub/Hub.Config.t.sol +++ b/tests/unit/Hub/Hub.Config.t.sol @@ -26,7 +26,7 @@ contract HubConfigTest is HubBase { function test_hub_deploy_reverts_on_InvalidConstructorInput() public { DeployWrapper deployer = new DeployWrapper(); - vm.expectRevert(); + vm.expectRevert(Create1Utils.Create1DeploymentFailed.selector); deployer.deployHub(address(0)); } diff --git a/tests/unit/Spoke/Spoke.Config.t.sol b/tests/unit/Spoke/Spoke.Config.t.sol index 855ffc245..f79e6ede6 100644 --- a/tests/unit/Spoke/Spoke.Config.t.sol +++ b/tests/unit/Spoke/Spoke.Config.t.sol @@ -25,7 +25,7 @@ contract SpokeConfigTest is SpokeBase { function test_spoke_deploy_reverts_on_InvalidConstructorInput() public { DeployWrapper deployer = new DeployWrapper(); - vm.expectRevert(); + vm.expectRevert(Create1Utils.Create1DeploymentFailed.selector); deployer.deploySpokeImplementation(address(0), Constants.MAX_ALLOWED_USER_RESERVES_LIMIT); } @@ -34,7 +34,7 @@ contract SpokeConfigTest is SpokeBase { address oracle = makeAddr('AaveOracle'); vm.mockCall(oracle, abi.encodeCall(IPriceOracle.DECIMALS, ()), abi.encode(7)); - vm.expectRevert(); + vm.expectRevert(Create1Utils.Create1DeploymentFailed.selector); deployer.deploySpokeImplementation(oracle, Constants.MAX_ALLOWED_USER_RESERVES_LIMIT); } @@ -43,7 +43,7 @@ contract SpokeConfigTest is SpokeBase { address oracle = makeAddr('AaveOracle'); vm.mockCall(oracle, abi.encodeCall(IPriceOracle.DECIMALS, ()), abi.encode(8)); - vm.expectRevert(); + vm.expectRevert(Create1Utils.Create1DeploymentFailed.selector); deployer.deploySpokeImplementation(oracle, 0); } From 842ecc475ccc91f56118cc7d35b0842093922fb9 Mon Sep 17 00:00:00 2001 From: Kogaroshi <25688223+Kogaroshi@users.noreply.github.com> Date: Tue, 17 Feb 2026 14:29:27 +0100 Subject: [PATCH 2/3] fix : pr comments & create2 new error --- tests/Create1Utils.sol | 3 +-- tests/Create2Utils.sol | 18 ++++++++---------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/tests/Create1Utils.sol b/tests/Create1Utils.sol index e0bc6d0b2..b7e815015 100644 --- a/tests/Create1Utils.sol +++ b/tests/Create1Utils.sol @@ -10,8 +10,7 @@ library Create1Utils { Vm internal constant vm = Vm(address(uint160(uint256(keccak256('hevm cheat code'))))); function create1Deploy(bytes memory bytecode) internal returns (address addr) { - /// @solidity memory-safe-assembly - assembly { + assembly ('memory-safe') { addr := create(0, add(bytecode, 0x20), mload(bytecode)) } require(addr != address(0), Create1DeploymentFailed()); diff --git a/tests/Create2Utils.sol b/tests/Create2Utils.sol index 383578260..14934ea46 100644 --- a/tests/Create2Utils.sol +++ b/tests/Create2Utils.sol @@ -7,6 +7,7 @@ import {Vm} from 'forge-std/Vm.sol'; library Create2Utils { error NoCreate2Factory(); error Create2DeploymentFailed(); + error Create2ContractAlreadyDeployed(); // https://github.com/safe-global/safe-singleton-factory address public constant CREATE2_FACTORY = 0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7; @@ -26,19 +27,16 @@ library Create2Utils { require(_isContractDeployed(CREATE2_FACTORY), NoCreate2Factory()); address computed = computeCreate2Address(salt, bytecode); + require(!_isContractDeployed(computed), Create2ContractAlreadyDeployed()); - if (_isContractDeployed(computed)) { - return computed; - } else { - bytes memory creationBytecode = abi.encodePacked(salt, bytecode); - bytes memory returnData; - (, returnData) = CREATE2_FACTORY.call(creationBytecode); + bytes memory creationBytecode = abi.encodePacked(salt, bytecode); + bytes memory returnData; + (, returnData) = CREATE2_FACTORY.call(creationBytecode); - address deployedAt = address(uint160(bytes20(returnData))); - require(deployedAt == computed, Create2DeploymentFailed()); + address deployedAt = address(uint160(bytes20(returnData))); + require(deployedAt == computed, Create2DeploymentFailed()); - return deployedAt; - } + return deployedAt; } function _isContractDeployed(address instance) internal view returns (bool) { From 689e7134cd04d3f4b6a5fc6efb815bc1c2521fd5 Mon Sep 17 00:00:00 2001 From: Kogaroshi <25688223+Kogaroshi@users.noreply.github.com> Date: Fri, 6 Mar 2026 13:42:43 +0100 Subject: [PATCH 3/3] fix : remove Create1Utils and use deployCode for Hub --- tests/Base.t.sol | 2 +- tests/Create1Utils.sol | 22 ---------------------- tests/DeployUtils.sol | 19 +++++-------------- tests/unit/Hub/Hub.Config.t.sol | 4 ++-- tests/unit/Spoke/Spoke.Config.t.sol | 6 +++--- 5 files changed, 11 insertions(+), 42 deletions(-) delete mode 100644 tests/Create1Utils.sol diff --git a/tests/Base.t.sol b/tests/Base.t.sol index efb0b63c8..b2b08826e 100644 --- a/tests/Base.t.sol +++ b/tests/Base.t.sol @@ -101,7 +101,7 @@ import { // test import {Constants} from 'tests/Constants.sol'; import {DeployUtils} from 'tests/DeployUtils.sol'; -import {Create1Utils} from 'tests/Create1Utils.sol'; +import {Create2Utils} from 'tests/Create2Utils.sol'; import {Utils} from 'tests/Utils.sol'; // mocks diff --git a/tests/Create1Utils.sol b/tests/Create1Utils.sol deleted file mode 100644 index b7e815015..000000000 --- a/tests/Create1Utils.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -// Copyright (c) 2025 Aave Labs -pragma solidity ^0.8.0; - -import {Vm} from 'forge-std/Vm.sol'; - -library Create1Utils { - error Create1DeploymentFailed(); - - Vm internal constant vm = Vm(address(uint160(uint256(keccak256('hevm cheat code'))))); - - function create1Deploy(bytes memory bytecode) internal returns (address addr) { - assembly ('memory-safe') { - addr := create(0, add(bytecode, 0x20), mload(bytecode)) - } - require(addr != address(0), Create1DeploymentFailed()); - } - - function computeCreate1Address(address deployer, uint256 nonce) internal pure returns (address) { - return vm.computeCreateAddress(deployer, nonce); - } -} diff --git a/tests/DeployUtils.sol b/tests/DeployUtils.sol index ac1b60d53..62de40b48 100644 --- a/tests/DeployUtils.sol +++ b/tests/DeployUtils.sol @@ -7,7 +7,6 @@ import {TransparentUpgradeableProxy} from 'src/dependencies/openzeppelin/Transpa import {IHub} from 'src/hub/interfaces/IHub.sol'; import {ISpoke} from 'src/spoke/interfaces/ISpoke.sol'; import {ISpokeInstance} from 'tests/mocks/ISpokeInstance.sol'; -import {Create1Utils} from 'tests/Create1Utils.sol'; import {Create2Utils} from 'tests/Create2Utils.sol'; library DeployUtils { @@ -17,10 +16,8 @@ library DeployUtils { address oracle, uint16 maxUserReservesLimit ) internal returns (ISpokeInstance) { - return - ISpokeInstance( - Create1Utils.create1Deploy(_getSpokeInstanceInitCode(oracle, maxUserReservesLimit)) - ); + bytes32 salt = keccak256(abi.encode(oracle, maxUserReservesLimit)); + return deploySpokeImplementation(oracle, maxUserReservesLimit, salt); } function deploySpokeImplementation( @@ -41,14 +38,8 @@ library DeployUtils { address proxyAdminOwner, bytes memory initData ) internal returns (ISpoke) { - return - ISpoke( - proxify( - address(deploySpokeImplementation(oracle, maxUserReservesLimit)), - proxyAdminOwner, - initData - ) - ); + bytes32 salt = keccak256(abi.encode(oracle, maxUserReservesLimit)); + return deploySpoke(oracle, maxUserReservesLimit, proxyAdminOwner, salt, initData); } function deploySpoke( @@ -80,7 +71,7 @@ library DeployUtils { } function deployHub(address authority) internal returns (IHub) { - return IHub(Create1Utils.create1Deploy(_getHubInitCode(authority))); + return IHub(vm.deployCode('src/hub/Hub.sol:Hub', abi.encode(authority))); } function deployHub(address authority, bytes32 salt) internal returns (IHub hub) { diff --git a/tests/unit/Hub/Hub.Config.t.sol b/tests/unit/Hub/Hub.Config.t.sol index 9ad04a52c..7d1a32fc4 100644 --- a/tests/unit/Hub/Hub.Config.t.sol +++ b/tests/unit/Hub/Hub.Config.t.sol @@ -23,10 +23,10 @@ contract HubConfigTest is HubBase { ); } - function test_hub_deploy_reverts_on_InvalidConstructorInput() public { + function test_hub_deploy_revertsWith_InvalidAddress() public { DeployWrapper deployer = new DeployWrapper(); - vm.expectRevert(Create1Utils.Create1DeploymentFailed.selector); + vm.expectRevert(IHub.InvalidAddress.selector); deployer.deployHub(address(0)); } diff --git a/tests/unit/Spoke/Spoke.Config.t.sol b/tests/unit/Spoke/Spoke.Config.t.sol index f79e6ede6..7238dfbf5 100644 --- a/tests/unit/Spoke/Spoke.Config.t.sol +++ b/tests/unit/Spoke/Spoke.Config.t.sol @@ -25,7 +25,7 @@ contract SpokeConfigTest is SpokeBase { function test_spoke_deploy_reverts_on_InvalidConstructorInput() public { DeployWrapper deployer = new DeployWrapper(); - vm.expectRevert(Create1Utils.Create1DeploymentFailed.selector); + vm.expectRevert(Create2Utils.Create2DeploymentFailed.selector); deployer.deploySpokeImplementation(address(0), Constants.MAX_ALLOWED_USER_RESERVES_LIMIT); } @@ -34,7 +34,7 @@ contract SpokeConfigTest is SpokeBase { address oracle = makeAddr('AaveOracle'); vm.mockCall(oracle, abi.encodeCall(IPriceOracle.DECIMALS, ()), abi.encode(7)); - vm.expectRevert(Create1Utils.Create1DeploymentFailed.selector); + vm.expectRevert(Create2Utils.Create2DeploymentFailed.selector); deployer.deploySpokeImplementation(oracle, Constants.MAX_ALLOWED_USER_RESERVES_LIMIT); } @@ -43,7 +43,7 @@ contract SpokeConfigTest is SpokeBase { address oracle = makeAddr('AaveOracle'); vm.mockCall(oracle, abi.encodeCall(IPriceOracle.DECIMALS, ()), abi.encode(8)); - vm.expectRevert(Create1Utils.Create1DeploymentFailed.selector); + vm.expectRevert(Create2Utils.Create2DeploymentFailed.selector); deployer.deploySpokeImplementation(oracle, 0); }