Skip to content

Commit

Permalink
feat: system contracts accept address provider as only constructor ar…
Browse files Browse the repository at this point in the history
…gument
  • Loading branch information
lekhovitsky committed Jan 15, 2025
1 parent 229d072 commit 66f9b8e
Show file tree
Hide file tree
Showing 16 changed files with 126 additions and 58 deletions.
11 changes: 8 additions & 3 deletions contracts/core/BotListV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@ import {
IncorrectBotPermissionsException,
InvalidBotException
} from "../interfaces/IExceptions.sol";
import {IAddressProvider} from "../interfaces/base/IAddressProvider.sol";
import {IBot} from "../interfaces/base/IBot.sol";

import {AP_INSTANCE_MANAGER_PROXY, NO_VERSION_CONTROL} from "../libraries/Constants.sol";

import {SanityCheckTrait} from "../traits/SanityCheckTrait.sol";

/// @title Bot list V3
Expand All @@ -37,9 +40,11 @@ contract BotListV3 is IBotListV3, SanityCheckTrait, Ownable {
mapping(address => mapping(address => EnumerableSet.AddressSet)) internal _activeBots;

/// @notice Constructor
/// @param owner_ Contract owner
constructor(address owner_) {
transferOwnership(owner_);
/// @param addressProvider_ Address provider contract address
constructor(address addressProvider_) {
transferOwnership(
IAddressProvider(addressProvider_).getAddressOrRevert(AP_INSTANCE_MANAGER_PROXY, NO_VERSION_CONTROL)
);
}

// ----------- //
Expand Down
11 changes: 8 additions & 3 deletions contracts/core/DefaultAccountFactoryV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import {
CreditAccountIsInUseException,
MasterCreditAccountAlreadyDeployedException
} from "../interfaces/IExceptions.sol";
import {IAddressProvider} from "../interfaces/base/IAddressProvider.sol";

import {AP_INSTANCE_MANAGER_PROXY, NO_VERSION_CONTROL} from "../libraries/Constants.sol";

/// @dev Struct holding factory and queue params for a credit manager
/// @param masterCreditAccount Address of the contract to clone to create new accounts for the credit manager
Expand Down Expand Up @@ -57,9 +60,11 @@ contract DefaultAccountFactoryV3 is IDefaultAccountFactoryV3, Ownable {
mapping(address => mapping(uint256 => QueuedAccount)) internal _queuedAccounts;

/// @notice Constructor
/// @param owner_ Contract owner
constructor(address owner_) {
transferOwnership(owner_);
/// @param addressProvider_ Address provider contract address
constructor(address addressProvider_) {
transferOwnership(
IAddressProvider(addressProvider_).getAddressOrRevert(AP_INSTANCE_MANAGER_PROXY, NO_VERSION_CONTROL)
);
}

/// @notice Provides a reusable credit account from the queue to the credit manager.
Expand Down
26 changes: 16 additions & 10 deletions contracts/core/GearStakingV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,17 @@ import {
VotingContractStatus
} from "../interfaces/IGearStakingV3.sol";
import "../interfaces/IExceptions.sol";
import {IAddressProvider} from "../interfaces/base/IAddressProvider.sol";
import {IVotingContract} from "../interfaces/base/IVotingContract.sol";

import {EPOCHS_TO_WITHDRAW, EPOCH_LENGTH} from "../libraries/Constants.sol";
import {
AP_GEAR_TOKEN,
AP_CROSS_CHAIN_GOVERNANCE_PROXY,
EPOCHS_TO_WITHDRAW,
EPOCH_LENGTH,
FIRST_EPOCH_TIMESTAMP,
NO_VERSION_CONTROL
} from "../libraries/Constants.sol";

import {ReentrancyGuardTrait} from "../traits/ReentrancyGuardTrait.sol";
import {SanityCheckTrait} from "../traits/SanityCheckTrait.sol";
Expand All @@ -39,7 +47,7 @@ contract GearStakingV3 is IGearStakingV3, Ownable, ReentrancyGuardTrait, SanityC
address public immutable override gear;

/// @notice Timestamp of the first epoch of voting
uint256 public immutable override firstEpochTimestamp;
uint256 public constant override firstEpochTimestamp = FIRST_EPOCH_TIMESTAMP;

/// @dev Mapping from user to their stake amount and tokens available for voting
mapping(address => UserVoteLockData) internal voteLockData;
Expand All @@ -63,14 +71,12 @@ contract GearStakingV3 is IGearStakingV3, Ownable, ReentrancyGuardTrait, SanityC
}

/// @notice Constructor
/// @param owner_ Contract owner
/// @param gear_ GEAR token address
/// @param firstEpochTimestamp_ Timestamp at which the first epoch should start.
/// Setting this too far into the future poses a risk of locking user deposits.
constructor(address owner_, address gear_, uint256 firstEpochTimestamp_) {
gear = gear_; // U:[GS-1]
firstEpochTimestamp = firstEpochTimestamp_; // U:[GS-1]
transferOwnership(owner_); // U:[GS-1]
/// @param addressProvider_ Address provider contract address
constructor(address addressProvider_) {
gear = IAddressProvider(addressProvider_).getAddressOrRevert(AP_GEAR_TOKEN, NO_VERSION_CONTROL); // U:[GS-1]
transferOwnership(
IAddressProvider(addressProvider_).getAddressOrRevert(AP_CROSS_CHAIN_GOVERNANCE_PROXY, NO_VERSION_CONTROL)
); // U:[GS-1]
}

/// @notice Stakes given amount of GEAR, and, optionally, performs a sequence of votes
Expand Down
8 changes: 8 additions & 0 deletions contracts/interfaces/base/IAddressProvider.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.17;

interface IAddressProvider {
function getAddressOrRevert(bytes32 key, uint256 version) external view returns (address);
}
8 changes: 7 additions & 1 deletion contracts/interfaces/base/IDegenNFT.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.17;

interface IDegenNFT {
import {IVersion} from "./IVersion.sol";

/// @title Degen NFT interface
/// @notice Generic interface for a Degen NFT contract that can be used to restrict
/// non-whitelisted users from opening accounts through the credit facade
/// @dev Degen NFTs must have type `DEGEN_NFT::{POSTFIX}`
interface IDegenNFT is IVersion {
function burn(address from, uint256 amount) external;
}
6 changes: 6 additions & 0 deletions contracts/libraries/Constants.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,18 @@
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.17;

bytes32 constant AP_GEAR_TOKEN = "GEAR_TOKEN";
bytes32 constant AP_INSTANCE_MANAGER_PROXY = "INSTANCE_MANAGER_PROXY";
bytes32 constant AP_CROSS_CHAIN_GOVERNANCE_PROXY = "CROSS_CHAIN_GOVERNANCE_PROXY";
uint256 constant NO_VERSION_CONTROL = 0;

uint256 constant WAD = 1e18;
uint256 constant RAY = 1e27;
uint16 constant PERCENTAGE_FACTOR = 1e4;

uint256 constant SECONDS_PER_YEAR = 365 days;
uint256 constant EPOCH_LENGTH = 7 days;
uint256 constant FIRST_EPOCH_TIMESTAMP = 1702900800;
uint256 constant EPOCHS_TO_WITHDRAW = 4;

uint8 constant MAX_WITHDRAW_FEE = 100;
Expand Down
1 change: 1 addition & 0 deletions contracts/test/helpers/IntegrationTestHelper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ contract IntegrationTestHelper is TestHelper, BalanceHelper, ConfigManager {
botList = gp.botList();
cr = gp.contractsRegister();
gearStaking = gp.gearStaking();
vm.warp(gearStaking.firstEpochTimestamp());

vm.stopPrank();
}
Expand Down
2 changes: 1 addition & 1 deletion contracts/test/integration/credit/Bots.int.sol
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ contract BotsIntegrationTest is IntegrationTestHelper, ICreditFacadeV3Events {
vm.prank(bot);
creditFacade.botMulticall(creditAccount, calls);

vm.prank(CONFIGURATOR);
vm.prank(botList.owner());
botList.forbidBot(bot);

vm.expectRevert(abi.encodeWithSelector(NotApprovedBotException.selector, (bot)));
Expand Down
22 changes: 16 additions & 6 deletions contracts/test/integration/governance/GaugeMigration.int.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ import {GaugeV3} from "../../../pool/GaugeV3.sol";
import {PoolQuotaKeeperV3} from "../../../pool/PoolQuotaKeeperV3.sol";

import {CallerNotGaugeException} from "../../../interfaces/IExceptions.sol";
import {AP_GEAR_TOKEN, FIRST_EPOCH_TIMESTAMP} from "../../../libraries/Constants.sol";

import {PoolMock} from "../../mocks/pool/PoolMock.sol";
import {ERC20Mock} from "../../mocks/token/ERC20Mock.sol";
import {AP_GEAR_TOKEN, AddressProviderV3ACLMock} from "../../mocks/core/AddressProviderV3ACLMock.sol";
import {AddressProviderV3ACLMock} from "../../mocks/core/AddressProviderV3ACLMock.sol";

/// @title Gauge migration integration test
/// @notice I:[GAM]: Tests that ensure that gauges can be migrated properly
Expand Down Expand Up @@ -48,7 +49,9 @@ contract GaugeMigrationIntegrationTest is Test {
vm.startPrank(configurator);
// deploy address provider, staking and pool
addressProvider = new AddressProviderV3ACLMock();
staking = new GearStakingV3(configurator, address(gear), block.timestamp);
addressProvider.setAddress(AP_GEAR_TOKEN, address(gear), false);

staking = new GearStakingV3(address(addressProvider));
pool = new PoolMock(address(addressProvider), address(underlying));

// deploy quota keeper and connect it to the pool
Expand All @@ -57,14 +60,17 @@ contract GaugeMigrationIntegrationTest is Test {

// deploy gauge and connect it to the quota keeper and staking
gauge = new GaugeV3(address(pool), address(staking));
staking.setVotingContractStatus(address(gauge), VotingContractStatus.ALLOWED);
quotaKeeper.setGauge(address(gauge));

// add tokens to the gauge
gauge.addQuotaToken({token: address(token1), minRate: 600, maxRate: 3000});
gauge.addQuotaToken({token: address(token2), minRate: 400, maxRate: 2000});
vm.stopPrank();

vm.prank(staking.owner());
staking.setVotingContractStatus(address(gauge), VotingContractStatus.ALLOWED);
vm.warp(FIRST_EPOCH_TIMESTAMP);

// do some voting
deal({token: address(gear), to: user1, give: 1_000_000e18});
deal({token: address(gear), to: user2, give: 2_000_000e18});
Expand Down Expand Up @@ -101,12 +107,14 @@ contract GaugeMigrationIntegrationTest is Test {
/// @notice I:[GAM-1]: Gauge migration works as expected
function test_I_GAM_01_gauge_migration_works_as_expected() public {
// prepare a new gauge and disable an old one
vm.startPrank(configurator);
GaugeV3 newGauge = new GaugeV3(address(pool), address(staking));

vm.startPrank(staking.owner());
staking.setVotingContractStatus(address(newGauge), VotingContractStatus.ALLOWED);
staking.setVotingContractStatus(address(gauge), VotingContractStatus.UNVOTE_ONLY);
vm.stopPrank();

vm.startPrank(configurator);
newGauge.addQuotaToken({token: address(token1), minRate: 600, maxRate: 3000});
newGauge.addQuotaToken({token: address(token2), minRate: 400, maxRate: 2000});
quotaKeeper.setGauge(address(newGauge));
Expand Down Expand Up @@ -165,16 +173,18 @@ contract GaugeMigrationIntegrationTest is Test {
/// @notice I:[GAM-2]: Gauge and staking migration works as expected
function test_I_GAM_02_gaude_and_staking_migration_works_as_expected() public {
// prepare new staking and gauge contracts
vm.startPrank(configurator);
GearStakingV3 newStaking = new GearStakingV3(configurator, address(gear), block.timestamp);
GearStakingV3 newStaking = new GearStakingV3(address(addressProvider));
GaugeV3 newGauge = new GaugeV3(address(pool), address(newStaking));

vm.startPrank(staking.owner());
newStaking.setMigrator(address(staking));
staking.setSuccessor(address(newStaking));

staking.setVotingContractStatus(address(gauge), VotingContractStatus.UNVOTE_ONLY);
newStaking.setVotingContractStatus(address(newGauge), VotingContractStatus.ALLOWED);
vm.stopPrank();

vm.startPrank(configurator);
newGauge.addQuotaToken({token: address(token1), minRate: 600, maxRate: 3000});
newGauge.addQuotaToken({token: address(token2), minRate: 400, maxRate: 2000});
quotaKeeper.setGauge(address(newGauge));
Expand Down
8 changes: 6 additions & 2 deletions contracts/test/interfaces/IAddressProviderV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@
// (c) Gearbox Foundation, 2023.
pragma solidity ^0.8.17;

uint256 constant NO_VERSION_CONTROL = 0;
import {
AP_GEAR_TOKEN,
AP_INSTANCE_MANAGER_PROXY,
AP_CROSS_CHAIN_GOVERNANCE_PROXY,
NO_VERSION_CONTROL
} from "../../libraries/Constants.sol";

bytes32 constant AP_ACCOUNT_FACTORY = "ACCOUNT_FACTORY";
bytes32 constant AP_ACL = "ACL";
bytes32 constant AP_BOT_LIST = "BOT_LIST";
bytes32 constant AP_CONTRACTS_REGISTER = "CONTRACTS_REGISTER";
bytes32 constant AP_GEAR_STAKING = "GEAR_STAKING";
bytes32 constant AP_GEAR_TOKEN = "GEAR_TOKEN";
bytes32 constant AP_PRICE_ORACLE = "PRICE_ORACLE";
bytes32 constant AP_TREASURY = "TREASURY";
bytes32 constant AP_WETH_TOKEN = "WETH_TOKEN";
Expand Down
3 changes: 3 additions & 0 deletions contracts/test/mocks/core/AddressProviderV3ACLMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ contract AddressProviderV3ACLMock is Test, IAddressProviderV3, Ownable {
_setAddress(AP_TREASURY, address(1234), 0);

_setAddress(AP_WETH_TOKEN, address(new WETHMock()), 0);

_setAddress(AP_INSTANCE_MANAGER_PROXY, makeAddr("INSTANCE_MANAGER_PROXY"), 0);
_setAddress(AP_CROSS_CHAIN_GOVERNANCE_PROXY, makeAddr("CROSS_CHAIN_GOVERNANCE_PROXY"), 0);
}

function isConfigurator(address addr) external view returns (bool) {
Expand Down
3 changes: 3 additions & 0 deletions contracts/test/mocks/token/DegenNFTMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import {IDegenNFT} from "../../../interfaces/base/IDegenNFT.sol";
import {InsufficientBalanceException} from "../../../interfaces/IExceptions.sol";

contract DegenNFTMock is ERC721, IDegenNFT {
uint256 public constant override version = 3_10;
bytes32 public constant override contractType = "DEGEN_NFT::MOCK";

address public minter;

constructor(string memory name, string memory symbol) ERC721(name, symbol) {
Expand Down
7 changes: 4 additions & 3 deletions contracts/test/suites/GenesisFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,13 @@ contract GenesisFactory is Ownable {

priceOracle = new PriceOracleV3(address(acl));
lossPolicy = new LossPolicyMock();
accountFactory = new DefaultAccountFactoryV3(msg.sender);
botList = new BotListV3(msg.sender);
accountFactory = new DefaultAccountFactoryV3(address(acl));
botList = new BotListV3(address(acl));

ERC20 gearToken = new ERC20("Gearbox", "GEAR");
acl.setAddress(AP_GEAR_TOKEN, address(gearToken), false);

gearStaking = new GearStakingV3(msg.sender, address(gearToken), 1);
gearStaking = new GearStakingV3(address(acl));

acl.grantRole("PAUSABLE_ADMIN", msg.sender);
acl.grantRole("UNPAUSABLE_ADMIN", msg.sender);
Expand Down
11 changes: 8 additions & 3 deletions contracts/test/unit/core/BotListV3.unit.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {IBotListV3Events} from "../../../interfaces/IBotListV3.sol";
import "../../lib/constants.sol";

// MOCKS
import {AddressProviderV3ACLMock} from "../../mocks/core/AddressProviderV3ACLMock.sol";
import {BotMock} from "../../mocks/core/BotMock.sol";

// EXCEPTIONS
Expand All @@ -19,6 +20,7 @@ import "../../../interfaces/IExceptions.sol";
/// @notice U:[BL]: Unit tests for bot list v3
contract BotListV3UnitTest is Test, IBotListV3Events {
BotListV3 botList;
address owner;

address bot;
address otherBot;
Expand All @@ -29,6 +31,8 @@ contract BotListV3UnitTest is Test, IBotListV3Events {
address invalidAccount;

function setUp() public {
AddressProviderV3ACLMock addressProvider = new AddressProviderV3ACLMock();

bot = address(new BotMock());
otherBot = address(new BotMock());
creditManager = makeAddr("CREDIT_MANAGER");
Expand All @@ -52,7 +56,8 @@ contract BotListV3UnitTest is Test, IBotListV3Events {
abi.encodeWithSignature("CreditAccountDoesNotExistException()")
);

botList = new BotListV3(CONFIGURATOR);
botList = new BotListV3(address(addressProvider));
owner = botList.owner();
}

/// @notice U:[BL-1]: `setBotPermissions` works correctly
Expand All @@ -72,7 +77,7 @@ contract BotListV3UnitTest is Test, IBotListV3Events {
vm.prank(creditFacade);
botList.setBotPermissions({bot: bot, creditAccount: creditAccount, permissions: 2});

vm.prank(CONFIGURATOR);
vm.prank(owner);
botList.forbidBot(otherBot);

vm.expectRevert(InvalidBotException.selector);
Expand Down Expand Up @@ -105,7 +110,7 @@ contract BotListV3UnitTest is Test, IBotListV3Events {
assertEq(bots.length, 1, "Incorrect active bots array length");
assertEq(bots[0], bot, "Incorrect address added to active bots list");

vm.prank(CONFIGURATOR);
vm.prank(owner);
botList.forbidBot(bot);

vm.expectEmit(true, true, true, true);
Expand Down
Loading

0 comments on commit 66f9b8e

Please sign in to comment.