diff --git a/contracts/GaugeController.sol b/contracts/GaugeController.sol index a7ae2066..7729f223 100644 --- a/contracts/GaugeController.sol +++ b/contracts/GaugeController.sol @@ -2,14 +2,14 @@ pragma solidity 0.8.6; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@pooltogether/owner-manager-contracts/contracts/Ownable.sol"; +import "@pooltogether/owner-manager-contracts/contracts/Manageable.sol"; import "./interfaces/IGaugeController.sol"; import "./interfaces/IGaugeReward.sol"; import "./libraries/TwabLib.sol"; import "./libraries/ExtendedSafeCastLib.sol"; -contract GaugeController is IGaugeController, Ownable { +contract GaugeController is IGaugeController, Manageable { using ExtendedSafeCastLib for uint256; struct GaugeInfo { @@ -183,7 +183,7 @@ contract GaugeController is IGaugeController, Ownable { * @param _to Receivzer of the deposited tokens * @param _amount Amount of tokens to be deposited */ - function deposit(address _to, uint256 _amount) public { + function deposit(address _to, uint256 _amount) external { balances[_to] += _amount; token.transferFrom(msg.sender, address(this), _amount); emit TokenDeposited(msg.sender, _amount); @@ -193,7 +193,7 @@ contract GaugeController is IGaugeController, Ownable { * @notice Withdraw tokens in GaugeController and increase User balance. * @param _amount Amount of tokens to be withdrawn */ - function withdraw(uint256 _amount) public { + function withdraw(uint256 _amount) external { balances[msg.sender] -= _amount; token.transfer(msg.sender, _amount); emit TokenWithdrawn(msg.sender, _amount); @@ -204,7 +204,7 @@ contract GaugeController is IGaugeController, Ownable { * @param _gauge Address of the Gauge * @param _amount Amount of tokens to be debited from the User balance and credited to the Gauge balance */ - function increaseGauge(address _gauge, uint256 _amount) public requireGauge(_gauge) { + function increaseGauge(address _gauge, uint256 _amount) external requireGauge(_gauge) { balances[msg.sender] -= _amount; userGaugeBalance[msg.sender][_gauge] += _amount; TwabLib.Account storage gaugeTwab = gaugeTwabs[_gauge]; @@ -221,7 +221,7 @@ contract GaugeController is IGaugeController, Ownable { * @param _gauge Address of the Gauge * @param _amount Amount of tokens to be debited from the Gauge balance and credited to the Gauge balance */ - function decreaseGauge(address _gauge, uint256 _amount) public requireGauge(_gauge) { + function decreaseGauge(address _gauge, uint256 _amount) external requireGauge(_gauge) { balances[msg.sender] += _amount; userGaugeBalance[msg.sender][_gauge] -= _amount; TwabLib.Account storage gaugeTwab = gaugeTwabs[_gauge]; @@ -233,31 +233,28 @@ contract GaugeController is IGaugeController, Ownable { emit GaugeDecreased(msg.sender, _gauge, _amount); } - /// @TODO: Add Governance/Executive authorization modifier/function. /** * @notice Add new gauge with "1e18" scale to the GaugeController. * @param _gauge Address of the Gauge */ - function addGauge(address _gauge) public { + function addGauge(address _gauge) external onlyOwner { _addGaugeWithScale(_gauge, 1 ether); } - /// @TODO: Add Governance/Executive authorization modifier/function. /** * @notice Add new gauge and target scale to the GaugeController. * @param _gauge Address of new Gauge * @param _scale Amount to scale new Gauge by */ - function addGaugeWithScale(address _gauge, uint256 _scale) public { + function addGaugeWithScale(address _gauge, uint256 _scale) external onlyOwner { _addGaugeWithScale(_gauge, _scale); } - /// @TODO: Add Governance/Executive authorization modifier/function. /** * @notice Remove gauge from the GaugeController. * @param _gauge Address of existing Gauge */ - function removeGauge(address _gauge) public { + function removeGauge(address _gauge) external onlyOwner { TwabLib.Account storage gaugeScaleTwab = gaugeScaleTwabs[_gauge]; TwabLib.AccountDetails memory twabDetails = gaugeScaleTwab.details; ( @@ -271,19 +268,18 @@ contract GaugeController is IGaugeController, Ownable { * @notice Set GaugeReward contract * @param _gaugeReward Address of the GaugeReward contract */ - function setGaugeReward(IGaugeReward _gaugeReward) external onlyOwner { + function setGaugeReward(IGaugeReward _gaugeReward) external onlyManagerOrOwner { require(address(_gaugeReward) != address(0), "GC/GaugeReward-not-zero-address"); gaugeReward = _gaugeReward; emit GaugeRewardSet(_gaugeReward); } - /// @TODO: Add Governance/Executive authorization modifier/function. /** * @notice Set Gauge target scale. * @param _gauge Address of existing Gauge * @param _scale Amount to scale existing Gauge by */ - function setGaugeScale(address _gauge, uint256 _scale) public { + function setGaugeScale(address _gauge, uint256 _scale) external onlyManagerOrOwner { TwabLib.Account storage gaugeScaleTwab = gaugeScaleTwabs[_gauge]; TwabLib.AccountDetails memory twabDetails = gaugeScaleTwab.details; if (twabDetails.balance > _scale) { diff --git a/test/GaugeController.test.ts b/test/GaugeController.test.ts index 05a75dc8..a7fe8171 100644 --- a/test/GaugeController.test.ts +++ b/test/GaugeController.test.ts @@ -12,6 +12,8 @@ const { parseEther: toWei } = utils; describe('GaugeController', () => { let owner: SignerWithAddress; + let manager: SignerWithAddress; + let wallet2: SignerWithAddress; let GaugeController: Contract; let GaugeReward: MockContract; let Token: Contract; @@ -23,7 +25,7 @@ describe('GaugeController', () => { const gaugeAddress = '0x0000000000000000000000000000000000000001'; before(async () => { - [owner] = await getSigners(); + [owner, manager, wallet2] = await getSigners(); GaugeControllerFactory = await ethers.getContractFactory('GaugeController'); GaugeRewardArtifact = await artifacts.readArtifact('GaugeReward'); TokenFactory = await ethers.getContractFactory('ERC20Mintable'); @@ -41,6 +43,7 @@ describe('GaugeController', () => { GaugeReward = await deployMockContract(owner, GaugeRewardArtifact.abi); await GaugeController.setGaugeReward(GaugeReward.address); + await GaugeController.setManager(manager.address); }); /** @@ -160,6 +163,29 @@ describe('GaugeController', () => { }); }); + /** + * @description Test addGauge(address _to) function + * -= Expected Behavior =- + * 1. require the `msg.sender` to be authorized to add a gauge + * 2. require the `gauge` DOES NOT exist + * 3. increase `gaugeTwab` TWAB with `1e18` + * 4. update the `gaugeTwab.details` with the updated `twabDetails` object + * 5. emit a AddGaugeWithScale event + */ + describe('addGauge(address _to)', () => { + it('should SUCCEED to add gauge to the gaugeScaleTwabs mapping', async () => { + await GaugeController.addGauge(gaugeAddress); + expect(await GaugeController.getGaugeScaleBalance(gaugeAddress)).to.eq( + '1000000000000000000', + ); + }); + + it('should FAIL to execute BECAUSE of unauthorized access', async () => { + const unauthorized = GaugeController.connect(wallet2); + expect(unauthorized.addGauge(gaugeAddress)).to.be.revertedWith('Ownable/caller-not-owner'); + }); + }); + /** * @description Test addGaugeWithScale(address _to, uint256 _scale) function * -= Expected Behavior =- @@ -176,6 +202,11 @@ describe('GaugeController', () => { '1000000000000000000', ); }); + + it('should FAIL to execute BECAUSE of unauthorized access', async () => { + const unauthorized = GaugeController.connect(wallet2); + expect(unauthorized.addGaugeWithScale(gaugeAddress, toWei('1'))).to.be.revertedWith('Ownable/caller-not-owner'); + }); }); /** @@ -192,6 +223,11 @@ describe('GaugeController', () => { await GaugeController.removeGauge(gaugeAddress); expect(await GaugeController.getGaugeScaleBalance(gaugeAddress)).to.eq('0'); }); + + it('should FAIL to execute BECAUSE of unauthorized access', async () => { + const unauthorized = GaugeController.connect(wallet2); + expect(unauthorized.removeGauge(gaugeAddress)).to.be.revertedWith('Ownable/caller-not-owner'); + }); }); /** @@ -220,8 +256,47 @@ describe('GaugeController', () => { '500000000000000000', ); }); + + it('should SUCCEED to DECREASE the scale on EXISTING gauge from MANAGER role', async () => { + await GaugeController.addGauge(gaugeAddress); + const gauge = GaugeController.connect(manager); + await gauge.setGaugeScale(gaugeAddress, toWei('0.5')); + expect(await GaugeController.getGaugeScaleBalance(gaugeAddress)).to.eq( + '500000000000000000', + ); + }); + + it('should FAIL to execute BECAUSE of unauthorized access', async () => { + await GaugeController.addGauge(gaugeAddress); + const unauthorized = GaugeController.connect(wallet2); + expect(unauthorized.setGaugeScale(gaugeAddress, toWei('2'))).to.be.revertedWith('Manageable/caller-not-manager-or-owner'); + }); }); + describe('setGaugeReward(IGaugeReward _gaugeReward)', () => { + it('should SUCCEED to SET a new GaugeReward address', async () => { + await GaugeController.addGauge(gaugeAddress); + await GaugeController.setGaugeReward('0x0000000000000000000000000000000000000001'); + expect(await GaugeController.gaugeReward()).to.eq( + '0x0000000000000000000000000000000000000001', + ); + }); + + it('should SUCCEED to SET a new GaugeReward address from MANAGER role', async () => { + await GaugeController.addGauge(gaugeAddress); + const gauge = GaugeController.connect(manager); + await gauge.setGaugeReward('0x0000000000000000000000000000000000000001'); + expect(await GaugeController.gaugeReward()).to.eq( + '0x0000000000000000000000000000000000000001', + ); + }); + + it('should FAIL to execute BECAUSE of unauthorized access', async () => { + const unauthorized = GaugeController.connect(wallet2); + expect(unauthorized.setGaugeReward('0x0000000000000000000000000000000000000001')).to.be.revertedWith('Manageable/caller-not-manager-or-owner'); + }); + }) + /** * @description Test getGaugeBalance(address _gauge) function * -= Expected Behavior =-