Skip to content

Commit

Permalink
fix: bot improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
Van0k committed Nov 25, 2022
1 parent 3bf31ea commit 452b892
Show file tree
Hide file tree
Showing 8 changed files with 209 additions and 38 deletions.
21 changes: 21 additions & 0 deletions contracts/credit/CreditConfigurator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,8 @@ contract CreditConfigurator is ICreditConfigurator, ACLTrait {

bool expirable = creditFacade().expirable();

address botList = creditFacade().botList();

// Sets Credit Facade to the new address
creditManager.upgradeCreditFacade(_creditFacade); // F:[CC-30]

Expand All @@ -556,6 +558,8 @@ contract CreditConfigurator is ICreditConfigurator, ACLTrait {

// Copies the expiration date if the contract is expirable
if (expirable) _setExpirationDate(expirationDate); // F: [CC-30]

if (botList != address(0)) _setBotList(botList);
}

emit CreditFacadeUpgraded(_creditFacade); // F:[CC-30]
Expand Down Expand Up @@ -749,6 +753,23 @@ contract CreditConfigurator is ICreditConfigurator, ACLTrait {
}
}

function setBotList(address botList) external configuratorOnly {
_setBotList(botList);
}

function _setBotList(address botList) internal {
address currentBotList = creditFacade().botList();

if (botList == address(0)) {
revert ZeroAddressException();
}

if (botList != currentBotList) {
creditFacade().setBotList(botList);
emit BotListUpdated(botList);
}
}

/// @dev Adds an address to the list of emergency liquidators
/// @param liquidator The address to add to the list
/// @notice Emergency liquidators are trusted addresses
Expand Down
47 changes: 21 additions & 26 deletions contracts/credit/CreditFacade.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { IPriceOracleV2 } from "../interfaces/IPriceOracle.sol";
import { IDegenNFT } from "../interfaces/IDegenNFT.sol";
import { IWETH } from "../interfaces/external/IWETH.sol";
import { IBlacklistHelper } from "../interfaces/IBlacklistHelper.sol";
import { IBotList } from "../interfaces/IBotList.sol";

// CONSTANTS

Expand Down Expand Up @@ -81,11 +82,8 @@ contract CreditFacade is ICreditFacade, ReentrancyGuard {
public
override transfersAllowed;

/// @dev A map from maintainers to borrowers they maintain
mapping(address => address) public maintainerToBorrower;

/// @dev A map from (borrower, maintainer) to maintainer status
mapping(address => mapping(address => bool)) approvedMaintainer;
/// @dev Contract containing the list of approval statuses for borrowers / bots
address public botList;

/// @dev Address of WETH
address public immutable wethAddress;
Expand Down Expand Up @@ -674,38 +672,38 @@ contract CreditFacade is ICreditFacade, ReentrancyGuard {
}
}

/// @dev Executes a batch of transactions within a Multicall from maintainer on behalf of a borrower
/// @dev Executes a batch of transactions within a Multicall from bot on behalf of a borrower
/// - Wraps ETH and sends it back to msg.sender, if value > 0
/// - Executes the Multicall
/// - Performs a fullCollateralCheck to verify that hf > 1 after all actions
/// @param borrower Borrower to perform the multicall for
/// @param calls The array of MultiCall structs encoding the operations to execute.
function maintainerMulticall(address borrower, MultiCall[] calldata calls)
function botMulticall(address borrower, MultiCall[] calldata calls)
external
payable
override
nonReentrant
{
// Checks that the maintainer is approved by the borrower
if (!approvedMaintainer[borrower][msg.sender]) {
revert NotApprovedMaintainerException();
// Checks that the bot is approved by the borrower and is not forbidden
if (
!IBotList(botList).approvedBot(borrower, msg.sender) ||
IBotList(botList).forbiddenBot(msg.sender)
) {
revert NotApprovedBotException(); // F: [FA-58]
}

// Checks that msg.sender has an account
address creditAccount = creditManager.getCreditAccountOrRevert(
borrower
);

// Wraps ETH and sends it back to msg.sender
_wrapETH(); // F:[FA-3F]

if (calls.length != 0) {
_multicall(calls, borrower, creditAccount, false, false);
_multicall(calls, borrower, creditAccount, false, false); // F: [FA-58]

// Performs a fullCollateralCheck
// During a multicall, all intermediary health checks are skipped,
// as one fullCollateralCheck at the end is sufficient
creditManager.fullCollateralCheck(creditAccount);
creditManager.fullCollateralCheck(creditAccount); // F: [FA-58]
}
}

Expand Down Expand Up @@ -1204,17 +1202,6 @@ contract CreditFacade is ICreditFacade, ReentrancyGuard {
} // F: [FA-54]
}

//
// MAINTAINERS
//

/// @dev Adds or removes allowance for a maintainer to execute multicall on behalf of sender
/// @param maintainer Maintainer address
/// @param status Whether allowance is added or removed
function setMaintainerStatus(address maintainer, bool status) external {
approvedMaintainer[msg.sender][maintainer] = status;
}

// GETTERS
//

Expand Down Expand Up @@ -1432,6 +1419,14 @@ contract CreditFacade is ICreditFacade, ReentrancyGuard {
limits.maxBorrowedAmount = _maxBorrowedAmount; // F:
}

/// @dev Sets the bot list for this Credit Facade
/// The bot list is used to determine whether an address has a right to
/// run multicalls for a borrower as a bot. The relationship is stored in a separate
/// contract for easier transferability
function setBotList(address _botList) external creditConfiguratorOnly {
botList = _botList;
}

//
// CONTRACT WATCHLIST CONFIGURATION AND GETTERS
//
Expand Down
29 changes: 29 additions & 0 deletions contracts/interfaces/IBotList.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Holdings, 2022
pragma solidity ^0.8.10;

/// @title IBotList
interface IBotList {
/// @dev Emits when a borrower enables or disables a bot for their account
event BotApprovalChanged(
address indexed borrower,
address indexed bot,
bool status
);

/// @dev Emits when a bot is forbidden system-wide
event BotForbiddenStatusChanged(address indexed bot, bool status);

/// @dev Sets approval from msg.sender to bot
function setBotStatus(address bot, bool status) external;

/// @dev Returns whether the bot is approved by the borrower
function approvedBot(address borrower, address bot)
external
view
returns (bool);

/// @dev Returns whether the bot is forbidden by the borrower
function forbiddenBot(address bot) external view returns (bool);
}
3 changes: 3 additions & 0 deletions contracts/interfaces/ICreditConfigurator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ interface ICreditConfiguratorEvents {

/// @dev Emits when an address is removed from the list of emergency liquidators
event EmergencyLiquidatorRemoved(address);

/// @dev Emits when the bot list is updated in Credit Facade
event BotListUpdated(address);
}

/// @dev CreditConfigurator Exceptions
Expand Down
8 changes: 4 additions & 4 deletions contracts/interfaces/ICreditFacade.sol
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,8 @@ interface ICreditFacadeExceptions is ICreditManagerV2Exceptions {
/// @dev Thrown when attempting to perform an action on behalf of a borrower that is blacklisted in the underlying token
error NotAllowedForBlacklistedAddressException();

/// @dev Thrown if maintainerMulticall is called by an address that is not a maintainer for a specified borrower
error NotApprovedMaintainerException();
/// @dev Thrown if botMulticall is called by an address that is not a bot for a specified borrower
error NotApprovedBotException();
}

interface ICreditFacade is
Expand Down Expand Up @@ -333,13 +333,13 @@ interface ICreditFacade is
/// @param calls The array of MultiCall structs encoding the operations to execute.
function multicall(MultiCall[] calldata calls) external payable;

/// @dev Executes a batch of transactions within a Multicall from maintainer on behalf of a borrower
/// @dev Executes a batch of transactions within a Multicall from bot on behalf of a borrower
/// - Wraps ETH and sends it back to msg.sender, if value > 0
/// - Executes the Multicall
/// - Performs a fullCollateralCheck to verify that hf > 1 after all actions
/// @param borrower Borrower the perform the multicall for
/// @param calls The array of MultiCall structs encoding the operations to execute.
function maintainerMulticall(address borrower, MultiCall[] calldata calls)
function botMulticall(address borrower, MultiCall[] calldata calls)
external
payable;

Expand Down
52 changes: 52 additions & 0 deletions contracts/support/BotList.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: BUSL-1.1
// Gearbox. Generalized leverage protocol that allows to take leverage and then use it across other DeFi protocols and platforms in a composable way.
// (c) Gearbox Holdings, 2022
pragma solidity ^0.8.10;

import { Address } from "@openzeppelin/contracts/utils/Address.sol";

import { ACLTrait } from "../core/ACLTrait.sol";
import { IBotList } from "../interfaces/IBotList.sol";

import { ZeroAddressException, AddressIsNotContractException } from "../interfaces/IErrors.sol";

/// @title BotList
/// @dev Used to store a mapping of borrowers => bots. A separate contract is used for transferability when
/// changing Credit Facades
contract BotList is ACLTrait, IBotList {
using Address for address;

/// @dev Mapping from (borrower, bot) to bot approval status
mapping(address => mapping(address => bool)) public approvedBot;

/// @dev Whether the bot is forbidden system-wide
mapping(address => bool) public forbiddenBot;

constructor(address _addressProvider) ACLTrait(_addressProvider) {}

/// @dev Adds or removes allowance for a bot to execute multicalls on behalf of sender
/// @param bot Bot address
/// @param status Whether allowance is added or removed
function setBotStatus(address bot, bool status) external {
if (bot == address(0)) {
revert ZeroAddressException();
}

if (!bot.isContract() && status) {
revert AddressIsNotContractException(bot);
}

approvedBot[msg.sender][bot] = status;

emit BotApprovalChanged(msg.sender, bot, status);
}

/// @dev Forbids the bot system-wide if it is known to be compromised
function setBotForbiddenStatus(address bot, bool status)
external
configuratorOnly
{
forbiddenBot[bot] = status;
emit BotForbiddenStatusChanged(bot, status);
}
}
43 changes: 43 additions & 0 deletions contracts/test/credit/CreditConfigurator.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { ICreditManagerV2, ICreditManagerV2Events } from "../../interfaces/ICred
import { ICreditConfiguratorEvents } from "../../interfaces/ICreditConfigurator.sol";
import { IAdapter } from "../../interfaces/adapters/IAdapter.sol";
import { UniversalAdapter } from "../../adapters/UniversalAdapter.sol";
import { BotList } from "../../support/BotList.sol";

//
import { PercentageMath, PERCENTAGE_FACTOR, PERCENTAGE_FACTOR } from "../../libraries/PercentageMath.sol";
Expand Down Expand Up @@ -476,6 +477,9 @@ contract CreditConfiguratorTest is
evm.expectRevert(CallerNotConfiguratorException.selector);
creditConfigurator.setLimitPerBlock(0);

evm.expectRevert(CallerNotConfiguratorException.selector);
creditConfigurator.setBotList(FRIEND);

evm.stopPrank();
}

Expand Down Expand Up @@ -1345,6 +1349,45 @@ contract CreditConfiguratorTest is
}
}

/// @dev [CC-30A]: uupgradeCreditFacade transfers bot list
function test_CC_30A_botList_is_transferred_on_CreditFacade_upgrade()
public
{
for (uint256 ms = 0; ms < 2; ms++) {
bool migrateSettings = ms != 0;

setUp();

address botList = address(
new BotList(address(cct.addressProvider()))
);

evm.prank(CONFIGURATOR);
creditConfigurator.setBotList(botList);

CreditFacade cf = new CreditFacade(
address(creditManager),
address(0),
address(0),
false
);

evm.prank(CONFIGURATOR);
creditConfigurator.upgradeCreditFacade(
address(cf),
migrateSettings
);

address botList2 = cf.botList();

assertEq(
botList2,
migrateSettings ? botList : address(0),
"Bot list was not transferred"
);
}
}

/// @dev [CC-31]: uupgradeCreditConfigurator upgrades creditConfigurator
function test_CC_31_upgradeCreditConfigurator_upgrades_creditConfigurator()
public
Expand Down
Loading

0 comments on commit 452b892

Please sign in to comment.