Skip to content

Commit

Permalink
Friendlier UX
Browse files Browse the repository at this point in the history
  • Loading branch information
alcueca committed Apr 20, 2024
1 parent 494e31d commit c1480dd
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 31 deletions.
34 changes: 31 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,37 @@ network.

## Gnosis Safe Wrapper

The [Gnosis Safe Wrapper](src/gnosissafe/GnosisSafeWrapper.sol) is intended for individual users to enable it as a
module in their Gnosis Safe, so that they can lend their own assets and earn a fee. Please let us know if you do it and
we'll add your Safe to the list above.
The [Gnosis Safe Wrapper](src/gnosissafe/GnosisSafeWrapper.sol) is intended for individual users to flash lend their own
assets held in a Gnosis Safe and earn a fee. To enable it, from your own Gnosis Safe, execute a transaction bundle to
enable the GnosisSafeWrapperFactory and set the fees for individual assets.

```
safe.enableModule(gnosisSafeWrapperFactory);
gnosisSafeWrapperFactory.lend(asset, fee);
...
```

or an override to lend all assets in the safe:

```
safe.enableModule(gnosisSafeWrapperFactory);
gnosisSafeWrapperFactory.lendAll(fee);
...
```

The `fee` parameter can be zero for free flash loans. To disable lending, execute from your safe the following command:

```
gnosisSafeWrapperFactory.disableLend(asset);
...
```

If you set a lending override, you can disable it to go back to individual asset configuration:

```
gnosisSafeWrapperFactory.disableLendAll();
...
```

## Flash Loans

Expand Down
35 changes: 26 additions & 9 deletions src/gnosissafe/GnosisSafeWrapperFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ contract GnosisSafeWrapperFactory {
}

/// @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.
/// 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) {
Expand Down Expand Up @@ -76,19 +77,35 @@ contract GnosisSafeWrapperFactory {
/// @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 {
function lend(address asset, uint248 fee) public {
GnosisSafeWrapper _lender = _getOrDeploy(msg.sender);
_lender.lend(asset, fee, enabled);
emit LendingDataSet(msg.sender, asset, fee, enabled);
_lender.lend(asset, fee, true);
emit LendingDataSet(msg.sender, asset, fee, true);
}

/// @dev Disable lending for an asset.
/// @param asset Address of the asset.
function disableLend(address asset) public {
GnosisSafeWrapper _lender = _getOrDeploy(msg.sender);
(uint248 fee,) = _lender.lending(asset);
_lender.lend(asset, fee, false);
emit LendingDataSet(msg.sender, asset, fee, false);
}

/// @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 {
function lendAll(uint248 fee) public {
GnosisSafeWrapper _lender = _getOrDeploy(msg.sender);
_lender.lendAll(fee, true);
emit LendingDataSet(msg.sender, ALL_ASSETS, fee, true);
}

/// @dev Disable the lending override for all assets.
/// @notice If you have individual lending data set for assets, this will not affect them.
function disableLendAll() public {
GnosisSafeWrapper _lender = _getOrDeploy(msg.sender);
_lender.lendAll(fee, enabled);
emit LendingDataSet(msg.sender, ALL_ASSETS, fee, enabled);
(uint248 fee,) = _lender.lending(ALL_ASSETS);
_lender.lendAll(fee, false);
emit LendingDataSet(msg.sender, ALL_ASSETS, fee, false);
}
}
38 changes: 19 additions & 19 deletions test/GnosisSafeWrapper.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@ contract GnosisSafeWrapperStateZeroTest is GnosisSafeWrapperStateZero {
assertEq(address(factory.lender(address(safe))), address(wrapper));
}

function test_lendDebug() external {
function test_lend() external {
console2.log("test_lend");
vm.prank(address(safe));
factory.lend(USDT, 10, true);
factory.lend(USDT, 10);
wrapper = factory.lender(address(safe));
(uint256 fee, bool enabled) = wrapper.lending(USDT);
assertEq(fee, 10);
Expand All @@ -75,7 +75,7 @@ contract GnosisSafeWrapperStateZeroTest is GnosisSafeWrapperStateZero {
function test_lendAll() external {
console2.log("test_lendAll");
vm.prank(address(safe));
factory.lendAll(10, true);
factory.lendAll(10);
wrapper = factory.lender(address(safe));
(uint256 fee, bool enabled) = wrapper.lending(wrapper.ALL_ASSETS());
assertEq(fee, 10);
Expand All @@ -98,16 +98,16 @@ abstract contract GnosisSafeWrapperWithWrapper is GnosisSafeWrapperStateZero {
vm.startPrank(address(safe));
wrapper = factory.lender();
safe.enableModule(address(wrapper));
factory.lend(USDT, 10, true);
factory.lend(USDT, 10);
vm.stopPrank();

borrower = new MockBorrower(wrapper);
}
}

contract GnosisSafeWrapperWithWrapperTest is GnosisSafeWrapperWithWrapper {
function test_setLendingData_unauthorized() external {
console2.log("test_setLendingData_unauthorized");
function test_lend_unauthorized() external {
console2.log("test_lend_unauthorized");
vm.expectRevert(
abi.encodeWithSelector(
IAccessControl.AccessControlUnauthorizedAccount.selector, address(this), wrapper.DEFAULT_ADMIN_ROLE()
Expand All @@ -121,27 +121,27 @@ contract GnosisSafeWrapperWithWrapperTest is GnosisSafeWrapperWithWrapper {
assertEq(wrapper.flashFee(USDT, 1e18), 1e15, "Flash fee not right");
}

function test_setLendingData_changeFee() external {
console2.log("test_setLendingData_changeFee");
function test_lend_changeFee() external {
console2.log("test_lend_changeFee");
vm.prank(address(safe));
factory.lend(USDT, 1, true);
factory.lend(USDT, 1);
assertEq(wrapper.flashFee(USDT, 1e18), 1e14, "Flash fee not right");
}

function test_setLendingDataAll_changeFee() external {
console2.log("test_setLendingDataAll_changeFee");
function test_lendAll_changeFee() external {
console2.log("test_lendAll_changeFee");
vm.prank(address(safe));
factory.lendAll(1, true);
factory.lendAll(1);
assertEq(wrapper.flashFee(USDT, 1e18), 1e14, "Flash fee not right");
deal(USDC, address(safe), 100e18);
assertEq(wrapper.flashFee(USDC, 1e18), 1e14, "Flash fee not right");
}

function test_setLendingDataAll_disable() external {
console2.log("test_setLendingDataAll_changeFee");
function test_lendAll_disable() external {
console2.log("test_lendAll_changeFee");
vm.startPrank(address(safe));
factory.lendAll(1, true);
factory.lendAll(1, false);
factory.lendAll(1);
factory.disableLendAll();
vm.stopPrank();
assertEq(wrapper.flashFee(USDT, 1e18), 1e15, "Flash fee not right");
}
Expand Down Expand Up @@ -188,10 +188,10 @@ contract GnosisSafeWrapperWithWrapperTest is GnosisSafeWrapperWithWrapper {
assertEq(borrower.flashFee(), fee);
}

function test_setLendingData_disable() external {
console2.log("test_setLendingData_disable");
function test_lend_disable() external {
console2.log("test_lend_disable");
vm.prank(address(safe));
factory.lend(USDT, 10, false);
factory.disableLend(USDT);
vm.expectRevert(abi.encodeWithSelector(GnosisSafeWrapper.UnsupportedAsset.selector, USDT));
borrower.flashBorrow(USDT, 1);
}
Expand Down

0 comments on commit c1480dd

Please sign in to comment.