Skip to content

Commit

Permalink
Merge pull request #97 from term-finance/operator-role
Browse files Browse the repository at this point in the history
operator role for auction submissions, management for parameter setting
  • Loading branch information
aazhou1 authored Nov 14, 2024
2 parents 804e3d1 + 26a373a commit 6890011
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 117 deletions.
3 changes: 3 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ src = 'src'
out = 'out'
libs = ['lib']
solc = "0.8.23"
via_ir = true
optimizer = true
optimizer_runs = 200

remappings = [
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
Expand Down
47 changes: 27 additions & 20 deletions src/Strategy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ contract Strategy is BaseStrategy, Pausable, AccessControl {
* @param _yearnVault The address of the Yearn vault
* @param _discountRateAdapter The address of the discount rate adapter
* @param _eventEmitter The address of the event emitter
* @param _governorAddress The address of the governor
* @param _operatorAddress The address of the operator
* @param _termController The address of the term controller
* @param _repoTokenConcentrationLimit The concentration limit for repoTokens
* @param _timeToMaturityThreshold The time to maturity threshold
Expand All @@ -57,7 +57,7 @@ contract Strategy is BaseStrategy, Pausable, AccessControl {
address _yearnVault;
address _discountRateAdapter;
address _eventEmitter;
address _governorAddress;
address _operatorAddress;
address _termController;
uint256 _repoTokenConcentrationLimit;
uint256 _timeToMaturityThreshold;
Expand All @@ -68,7 +68,7 @@ contract Strategy is BaseStrategy, Pausable, AccessControl {
struct StrategyState {
address assetVault;
address eventEmitter;
address governorAddress;
address operatorAddress;
address prevTermController;
address currTermController;
address discountRateAdapter;
Expand All @@ -90,7 +90,7 @@ contract Strategy is BaseStrategy, Pausable, AccessControl {
error ZeroPurchaseTokenAmount();
error OfferNotFound();

bytes32 internal constant GOVERNOR_ROLE = keccak256("GOVERNOR_ROLE");
bytes32 internal constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE");

// Immutable state variables
ITermVaultEvents internal immutable TERM_VAULT_EVENT_EMITTER;
Expand Down Expand Up @@ -128,23 +128,23 @@ contract Strategy is BaseStrategy, Pausable, AccessControl {
/**
* @notice Pause the contract
*/
function pauseDeposit() external onlyRole(GOVERNOR_ROLE) {
function pauseDeposit() external onlyManagement {
depositLock = true;
TERM_VAULT_EVENT_EMITTER.emitDepositPaused();
}

/**
* @notice Unpause the contract
*/
function unpauseDeposit() external onlyRole(GOVERNOR_ROLE) {
function unpauseDeposit() external onlyManagement {
depositLock = false;
TERM_VAULT_EVENT_EMITTER.emitDepositUnpaused();
}

/**
* @notice Pause the contract
*/
function pauseStrategy() external onlyRole(GOVERNOR_ROLE) {
function pauseStrategy() external onlyManagement {
_pause();
depositLock = true;
TERM_VAULT_EVENT_EMITTER.emitStrategyPaused();
Expand All @@ -153,7 +153,7 @@ contract Strategy is BaseStrategy, Pausable, AccessControl {
/**
* @notice Unpause the contract
*/
function unpauseStrategy() external onlyRole(GOVERNOR_ROLE) {
function unpauseStrategy() external onlyManagement {
_unpause();
depositLock = false;
TERM_VAULT_EVENT_EMITTER.emitStrategyUnpaused();
Expand All @@ -165,7 +165,7 @@ contract Strategy is BaseStrategy, Pausable, AccessControl {
*/
function setTermController(
address newTermControllerAddr
) external onlyRole(GOVERNOR_ROLE) {
) external onlyManagement {
require(newTermControllerAddr != address(0));
require(ITermController(newTermControllerAddr).getProtocolReserveAddress() != address(0));
ITermController newTermController = ITermController(newTermControllerAddr);
Expand All @@ -183,6 +183,8 @@ contract Strategy is BaseStrategy, Pausable, AccessControl {
);
prevTermController = ITermController(current);
currTermController = newTermController;
strategyState.prevTermController = current;
strategyState.currTermController = newTermControllerAddr;
}

/**
Expand All @@ -191,14 +193,15 @@ contract Strategy is BaseStrategy, Pausable, AccessControl {
*/
function setDiscountRateAdapter(
address newAdapter
) external onlyRole(GOVERNOR_ROLE) {
) external onlyManagement {
ITermDiscountRateAdapter newDiscountRateAdapter = ITermDiscountRateAdapter(newAdapter);
require(address(newDiscountRateAdapter.currTermController()) != address(0));
TERM_VAULT_EVENT_EMITTER.emitDiscountRateAdapterUpdated(
address(discountRateAdapter),
newAdapter
);
discountRateAdapter = newDiscountRateAdapter;
strategyState.discountRateAdapter = newAdapter;
}

/**
Expand All @@ -207,12 +210,13 @@ contract Strategy is BaseStrategy, Pausable, AccessControl {
*/
function setTimeToMaturityThreshold(
uint256 newTimeToMaturityThreshold
) external onlyRole(GOVERNOR_ROLE) {
) external onlyManagement {
TERM_VAULT_EVENT_EMITTER.emitTimeToMaturityThresholdUpdated(
timeToMaturityThreshold,
newTimeToMaturityThreshold
);
timeToMaturityThreshold = newTimeToMaturityThreshold;
strategyState.timeToMaturityThreshold = newTimeToMaturityThreshold;
}

/**
Expand All @@ -222,12 +226,13 @@ contract Strategy is BaseStrategy, Pausable, AccessControl {
*/
function setRequiredReserveRatio(
uint256 newRequiredReserveRatio
) external onlyRole(GOVERNOR_ROLE) {
) external onlyManagement {
TERM_VAULT_EVENT_EMITTER.emitRequiredReserveRatioUpdated(
requiredReserveRatio,
newRequiredReserveRatio
);
requiredReserveRatio = newRequiredReserveRatio;
strategyState.requiredReserveRatio = newRequiredReserveRatio;
}

/**
Expand All @@ -236,12 +241,13 @@ contract Strategy is BaseStrategy, Pausable, AccessControl {
*/
function setRepoTokenConcentrationLimit(
uint256 newRepoTokenConcentrationLimit
) external onlyRole(GOVERNOR_ROLE) {
) external onlyManagement {
TERM_VAULT_EVENT_EMITTER.emitRepoTokenConcentrationLimitUpdated(
repoTokenConcentrationLimit,
newRepoTokenConcentrationLimit
);
repoTokenConcentrationLimit = newRepoTokenConcentrationLimit;
strategyState.repoTokenConcentrationLimit = newRepoTokenConcentrationLimit;
}

/**
Expand All @@ -250,12 +256,13 @@ contract Strategy is BaseStrategy, Pausable, AccessControl {
*/
function setDiscountRateMarkup(
uint256 newDiscountRateMarkup
) external onlyRole(GOVERNOR_ROLE) {
) external onlyManagement {
TERM_VAULT_EVENT_EMITTER.emitDiscountRateMarkupUpdated(
discountRateMarkup,
newDiscountRateMarkup
);
discountRateMarkup = newDiscountRateMarkup;
strategyState.discountRateMarkup = newDiscountRateMarkup;
}
/**
* @notice Set the collateral token parameters
Expand All @@ -265,15 +272,15 @@ contract Strategy is BaseStrategy, Pausable, AccessControl {
function setCollateralTokenParams(
address tokenAddr,
uint256 minCollateralRatio
) external onlyRole(GOVERNOR_ROLE) {
) external onlyManagement {
TERM_VAULT_EVENT_EMITTER.emitMinCollateralRatioUpdated(
tokenAddr,
minCollateralRatio
);
repoTokenListData.collateralTokenParams[tokenAddr] = minCollateralRatio;
}

function setRepoTokenBlacklist(address repoToken, bool blacklisted) external onlyRole(GOVERNOR_ROLE) {
function setRepoTokenBlacklist(address repoToken, bool blacklisted) external onlyManagement {
TERM_VAULT_EVENT_EMITTER.emitRepoTokenBlacklistUpdated(repoToken, blacklisted);
repoTokenBlacklist[repoToken] = blacklisted;
}
Expand Down Expand Up @@ -864,7 +871,7 @@ contract Strategy is BaseStrategy, Pausable, AccessControl {
external
whenNotPaused
notBlacklisted(repoToken)
onlyManagement
onlyRole(OPERATOR_ROLE)
returns (bytes32[] memory offerIds)
{
if(purchaseTokenAmount == 0) {
Expand Down Expand Up @@ -1019,7 +1026,7 @@ contract Strategy is BaseStrategy, Pausable, AccessControl {
function deleteAuctionOffers(
address termAuction,
bytes32[] calldata offerIds
) external onlyManagement {
) external onlyRole(OPERATOR_ROLE) {
// Validate if the term auction is deployed by term
if (!_isTermDeployed(termAuction)) {
revert InvalidTermAuction(termAuction);
Expand Down Expand Up @@ -1182,7 +1189,7 @@ contract Strategy is BaseStrategy, Pausable, AccessControl {
strategyState = StrategyState({
assetVault: address(YEARN_VAULT),
eventEmitter: address(TERM_VAULT_EVENT_EMITTER),
governorAddress: _params._governorAddress,
operatorAddress: _params._operatorAddress,
prevTermController: address(0),
currTermController: address(currTermController),
discountRateAdapter: address(discountRateAdapter),
Expand All @@ -1192,7 +1199,7 @@ contract Strategy is BaseStrategy, Pausable, AccessControl {
repoTokenConcentrationLimit: repoTokenConcentrationLimit
});

_grantRole(GOVERNOR_ROLE, _params._governorAddress);
_grantRole(OPERATOR_ROLE, _params._operatorAddress);
}

/*//////////////////////////////////////////////////////////////
Expand Down
34 changes: 15 additions & 19 deletions src/test/TestUSDCIntegration.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ contract TestUSDCIntegration is Setup {
repoToken1MonthAuction = new MockTermAuction(repoToken1Month);
repoToken1YearAuction = new MockTermAuction(repoToken1Year);

vm.startPrank(governor);
vm.startPrank(management);
termStrategy.setCollateralTokenParams(address(mockCollateral), 0.5e18);
termStrategy.setTimeToMaturityThreshold(3 weeks);
termStrategy.setRepoTokenConcentrationLimit(1e18);
Expand All @@ -78,12 +78,12 @@ contract TestUSDCIntegration is Setup {

function _submitOffer(bytes32 idHash, uint256 offerAmount, MockTermAuction auction, MockTermRepoToken repoToken) private returns (bytes32) {
// test: only management can submit offers
vm.expectRevert("!management");
vm.expectRevert();
bytes32[] memory offerIds = termStrategy.submitAuctionOffer(
auction, address(repoToken), idHash, bytes32("test price"), offerAmount
);

vm.prank(management);
vm.prank(operator);
offerIds = termStrategy.submitAuctionOffer(
auction, address(repoToken), idHash, bytes32("test price"), offerAmount
);
Expand Down Expand Up @@ -248,7 +248,7 @@ contract TestUSDCIntegration is Setup {

termController.setOracleRate(repoToken1Month.termRepoId(), 0.05e6);

vm.startPrank(governor);
vm.startPrank(management);
termStrategy.setCollateralTokenParams(address(mockCollateral), 0.5e18);
termStrategy.setTimeToMaturityThreshold(3 weeks);
vm.stopPrank();
Expand All @@ -266,7 +266,7 @@ contract TestUSDCIntegration is Setup {
function testSuccessfulUnlockedOfferFromCancelledAuction() public {
address testUser = vm.addr(0x11111);

vm.prank(management);
vm.prank(operator);
termStrategy.submitAuctionOffer(
repoToken1WeekAuction, address(repoToken1Week), bytes32("offer 1"), bytes32("test price"), 1e6
);
Expand Down Expand Up @@ -303,11 +303,11 @@ contract TestUSDCIntegration is Setup {
function testRepoTokenBlacklist() public {
address testUser = vm.addr(0x11111);
vm.prank(testUser);
vm.expectRevert();
vm.expectRevert("!management");
termStrategy.setRepoTokenBlacklist(address(repoToken1Week), true);
vm.stopPrank();

vm.prank(governor);
vm.prank(management);
termStrategy.setRepoTokenBlacklist(address(repoToken1Week), true);
vm.stopPrank();

Expand All @@ -320,13 +320,13 @@ contract TestUSDCIntegration is Setup {
address testUser = vm.addr(0x11111);
mockUSDC.mint(testUser, 1e18);
vm.prank(testUser);
vm.expectRevert();
vm.expectRevert("!management");
termStrategy.pauseDeposit();
vm.expectRevert();
vm.expectRevert("!management");
termStrategy.unpauseDeposit();
vm.stopPrank();

vm.prank(governor);
vm.prank(management);
termStrategy.pauseDeposit();
vm.stopPrank();

Expand All @@ -338,7 +338,7 @@ contract TestUSDCIntegration is Setup {
IERC4626(address(termStrategy)).deposit(1e6, testUser);
vm.stopPrank();

vm.prank(governor);
vm.prank(management);
termStrategy.unpauseDeposit();
vm.stopPrank();

Expand All @@ -354,21 +354,17 @@ contract TestUSDCIntegration is Setup {
TermDiscountRateAdapter valid = new TermDiscountRateAdapter(address(termController), adminWallet);

vm.prank(testUser);
vm.expectRevert();
vm.expectRevert("!management");
termStrategy.setDiscountRateAdapter(address(valid));

vm.prank(governor);
vm.expectRevert();
termStrategy.setDiscountRateAdapter(address(invalid));

vm.prank(governor);
vm.prank(management);
termStrategy.setDiscountRateAdapter(address(valid));
vm.stopPrank();

(
address assetVault,
address assetVault,
address eventEmitter,
address governorAddr,
address operatorAddr,
address prevTermController,
address currTermController,
address discountRateAdapter,
Expand Down
Loading

0 comments on commit 6890011

Please sign in to comment.