Skip to content

Commit

Permalink
Removed code duplication and unnecessary storage
Browse files Browse the repository at this point in the history
  • Loading branch information
alcueca committed Apr 20, 2024
1 parent a7f5108 commit fa88a93
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 34 deletions.
71 changes: 47 additions & 24 deletions src/gnosissafe/GnosisSafeWrapperFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,64 +6,87 @@ import { Clones } from "@openzeppelin/contracts/proxy/Clones.sol";
import { GnosisSafeWrapper } from "./GnosisSafeWrapper.sol";

contract GnosisSafeWrapperFactory {
event LenderCreated(address indexed safe, GnosisSafeWrapper lender);
event LenderCreated(address indexed safe, GnosisSafeWrapper _lender);
event LendingDataSet(address indexed safe, address indexed asset, uint248 fee, bool enabled);

address public constant ALL_ASSETS = address(0);

GnosisSafeWrapper public immutable template;

mapping(address safe => GnosisSafeWrapper lender) public lenders;

constructor() {
template = new GnosisSafeWrapper();
}

function _deploy(address safe) internal returns (GnosisSafeWrapper lender) {
lender = GnosisSafeWrapper(Clones.cloneDeterministic(address(template), bytes20(safe)));
lender.initialize(safe);
lenders[safe] = lender;
emit LenderCreated(safe, lender);
/// @dev Returns true if `_lender` is a contract.
/// @param _lender The address being checked.
// This method relies on extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
function _deployed(GnosisSafeWrapper _lender) internal view returns (bool) {
return address(_lender).code.length > 0;
}

function deploy(address safe) public returns (GnosisSafeWrapper lender) {
lender = _deploy(safe);
/// @dev Deploy a new Gnosis Safe wrapper for a Gnosis Safe.
/// The factory will become the owner of the wrapper, and the safe will be able to govern the wrapper through the factory.
/// There can ever be only one wrapper per safe
/// @param safe Address of the Gnosis Safe.
function _deploy(address safe) internal returns (GnosisSafeWrapper _lender) {
_lender = GnosisSafeWrapper(Clones.cloneDeterministic(address(template), bytes20(safe)));
_lender.initialize(safe);
emit LenderCreated(safe, _lender);
}

function predictLenderAddress(address safe) public view returns (address lender) {
lender = Clones.predictDeterministicAddress(address(template), bytes20(safe));
function _getOrDeploy(address safe) internal returns (GnosisSafeWrapper _lender) {
_lender = lender(safe);
if (!_deployed(_lender)) _lender = _deploy(safe);
}

function myLender() public view returns (address lender) {
lender = Clones.predictDeterministicAddress(address(template), bytes20(msg.sender));
/// @dev Deploy a new Gnosis Safe wrapper for a Gnosis Safe.
/// @param safe Address of the Gnosis Safe.
function deploy(address safe) public returns (GnosisSafeWrapper _lender) {
_lender = _deploy(safe);
}

function lending(address asset) public view returns (uint248 fee, bool enabled) {
return lenders[msg.sender].lending(asset);
/// @dev Get the Gnosis Safe wrapper for a Gnosis Safe.
/// @param safe Address of the Gnosis Safe.
function lender(address safe) public view returns (GnosisSafeWrapper _lender) {
_lender = GnosisSafeWrapper(Clones.predictDeterministicAddress(address(template), bytes20(safe)));
}

/// @dev Get the Gnosis Safe wrapper for the sender.
function lender() public view returns (GnosisSafeWrapper _lender) {
_lender = lender(msg.sender);
}

/// @dev Get the lending data for a Gnosis Safe and asset.
/// @param safe Address of the Gnosis Safe.
/// @param asset Address of the asset.
function lending(address safe, address asset) public view returns (uint248 fee, bool enabled) {
return lenders[safe].lending(asset);
return lender(safe).lending(asset);
}

/// @dev Get the lending data for an asset for the sender.
/// @param asset Address of the asset.
function lending(address asset) public view returns (uint248 fee, bool enabled) {
return lending(msg.sender, asset);
}

/// @dev Set lending data for an asset.
/// @param asset Address of the asset.
/// @param fee Fee for the flash loan (FP 1e-4)
/// @param enabled Whether the asset is enabled for flash loans.
function lend(address asset, uint248 fee, bool enabled) public {
GnosisSafeWrapper lender = lenders[msg.sender];
if (lender == GnosisSafeWrapper(address(0))) lender = _deploy(msg.sender);
lender.lend(asset, fee, enabled);
GnosisSafeWrapper _lender = _getOrDeploy(msg.sender);
_lender.lend(asset, fee, enabled);
emit LendingDataSet(msg.sender, asset, fee, enabled);
}

/// @dev Set a lending data override for all assets.
/// @param fee Fee for the flash loan (FP 1e-4)
/// @param enabled Whether the lending data override is enabled for flash loans.
function lendAll(uint248 fee, bool enabled) public {
GnosisSafeWrapper lender = lenders[msg.sender];
if (lender == GnosisSafeWrapper(address(0))) lender = _deploy(msg.sender);
lender.lendAll(fee, enabled);
emit LendingDataSet(msg.sender, address(0), fee, enabled);
GnosisSafeWrapper _lender = _getOrDeploy(msg.sender);
_lender.lendAll(fee, enabled);
emit LendingDataSet(msg.sender, ALL_ASSETS, fee, enabled);
}
}
23 changes: 13 additions & 10 deletions test/GnosisSafeWrapper.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ abstract contract GnosisSafeWrapperStateZero is Test {
address internal USDC;
IGnosisSafe internal safe;

function _deployed(GnosisSafeWrapper _lender) internal view returns (bool) {
return address(_lender).code.length > 0;
}

/// @dev A function invoked before each test case is run.
function setUp() public virtual {
// Revert if there is no API key.
Expand All @@ -49,21 +53,20 @@ contract GnosisSafeWrapperStateZeroTest is GnosisSafeWrapperStateZero {
function test_deploy() external {
console2.log("test_deploy");
wrapper = factory.deploy(address(safe));
assertEq(address(factory.lenders(address(safe))), address(wrapper));
assertEq(address(wrapper.safe()), address(safe));
}

function test_predictLenderAddressDebug() external {
console2.log("test_predictLenderAddress");
function test_lender() external {
console2.log("test_lender");
wrapper = factory.deploy(address(safe));
assertEq(factory.predictLenderAddress(address(safe)), address(wrapper));
assertEq(address(factory.lender(address(safe))), address(wrapper));
}

function test_lendDebug() external {
console2.log("test_lend");
vm.prank(address(safe));
factory.lend(USDT, 10, true);
wrapper = GnosisSafeWrapper(factory.predictLenderAddress(address(safe)));
wrapper = factory.lender(address(safe));
(uint256 fee, bool enabled) = wrapper.lending(USDT);
assertEq(fee, 10);
assertEq(enabled, true);
Expand All @@ -73,17 +76,17 @@ contract GnosisSafeWrapperStateZeroTest is GnosisSafeWrapperStateZero {
console2.log("test_lendAll");
vm.prank(address(safe));
factory.lendAll(10, true);
wrapper = GnosisSafeWrapper(factory.predictLenderAddress(address(safe)));
wrapper = factory.lender(address(safe));
(uint256 fee, bool enabled) = wrapper.lending(wrapper.ALL_ASSETS());
assertEq(fee, 10);
assertEq(enabled, true);
}

function test_myLender() external {
console2.log("test_myLender");
function test_lenderNoParams() external {
console2.log("test_lenderNoParams");
vm.startPrank(address(safe));
wrapper = factory.deploy(address(safe));
assertEq(factory.myLender(), address(wrapper));
assertEq(address(factory.lender()), address(wrapper));
vm.stopPrank();
}
}
Expand All @@ -93,7 +96,7 @@ abstract contract GnosisSafeWrapperWithWrapper is GnosisSafeWrapperStateZero {
super.setUp();

vm.startPrank(address(safe));
wrapper = GnosisSafeWrapper(factory.myLender());
wrapper = factory.lender();
safe.enableModule(address(wrapper));
factory.lend(USDT, 10, true);
vm.stopPrank();
Expand Down

0 comments on commit fa88a93

Please sign in to comment.