diff --git a/contracts/staking/TokenStaking.sol b/contracts/staking/TokenStaking.sol index 1347cbe0..99d7e41b 100644 --- a/contracts/staking/TokenStaking.sol +++ b/contracts/staking/TokenStaking.sol @@ -330,53 +330,6 @@ contract TokenStaking is Initializable, IStaking, Checkpoints { cleanAuthorizedApplications(stakingProviderStruct, 1); } - /// @notice Forced deauthorization of stake above 15m T. - /// Can be called by anyone. - function forceAuthorizationCap(address[] memory _stakingProviders) - external - { - require(_stakingProviders.length > 0, "Wrong input parameters"); - for (uint256 i = 0; i < _stakingProviders.length; i++) { - forceAuthorizationCap(_stakingProviders[i]); - } - } - - /// @notice Allows to instantly deauthorize up to 50% of max authorization. - /// Can be called only by the delegation owner or the staking - /// provider. - function optOutDecreaseAuthorization(address stakingProvider, uint96 amount) - public - onlyAuthorizerOf(stakingProvider) - { - require(amount > 0, "Parameters must be specified"); - StakingProviderInfo storage stakingProviderStruct = stakingProviders[ - stakingProvider - ]; - ( - uint96 availableToOptOut, - uint96 maxAuthorization - ) = getAvailableOptOutAmount(stakingProvider, stakingProviderStruct); - if (maxAuthorization > MAX_STAKE) { - forceDecreaseAuthorization(stakingProvider, MAX_STAKE); - maxAuthorization = MAX_STAKE; - availableToOptOut = HALF_MAX_STAKE; - } - require(availableToOptOut >= amount, "Opt-out amount too high"); - forceDecreaseAuthorization(stakingProvider, maxAuthorization - amount); - stakingProviderStruct.optOutAmount += amount; - } - - /// @notice Forced deauthorization of Beta stakers. - /// Can be called only by the governance. - function forceBetaStakerDecreaseAuthorization(address[] memory betaStakers) - external - { - require(betaStakers.length > 0, "Wrong input parameters"); - for (uint256 i = 0; i < betaStakers.length; i++) { - forceBetaStakerDecreaseAuthorization(betaStakers[i]); - } - } - /// @notice Pauses the given application’s eligibility to slash stakes. /// Besides that stakers can't change authorization to the application. /// Can be called only by the Panic Button of the particular @@ -651,48 +604,41 @@ contract TokenStaking is Initializable, IStaking, Checkpoints { /// application. See `IApplication`. function requestAuthorizationDecrease( address stakingProvider, - address, + address application, uint96 amount ) public override onlyAuthorizerOf(stakingProvider) { - optOutDecreaseAuthorization(stakingProvider, amount); - } - - /// @notice Forced deauthorization of Beta staker. - /// Can be called only by the governance. - function forceBetaStakerDecreaseAuthorization(address betaStaker) - public - onlyGovernance - { - StakingProviderInfo storage stakingProviderStruct = stakingProviders[ - betaStaker + require(!skipApplication(application), "Application is deprecated"); + ApplicationInfo storage applicationStruct = applicationInfo[ + application ]; - uint256 authorizedApplications = stakingProviderStruct - .authorizedApplications - .length; + require( + applicationStruct.status == ApplicationStatus.APPROVED, + "Application is not approved" + ); - require(authorizedApplications > 0, "Nothing was authorized"); - uint256 temp = 0; - for (uint256 i = 0; i < authorizedApplications; i++) { - address application = stakingProviderStruct.authorizedApplications[ - i - ]; - if (skipApplication(application)) { - continue; - } - forceDecreaseAuthorization( - betaStaker, - stakingProviderStruct, - application - ); - temp++; - } - cleanAuthorizedApplications(stakingProviderStruct, temp); - } + require(amount > 0, "Parameters must be specified"); - /// @notice Forced deauthorization of stake above 15m T. - /// Can be called by anyone. - function forceAuthorizationCap(address stakingProvider) public { - forceDecreaseAuthorization(stakingProvider, MAX_STAKE); + AppAuthorization storage authorization = stakingProviders[ + stakingProvider + ].authorizations[application]; + require( + authorization.authorized >= amount, + "Amount exceeds authorized" + ); + + authorization.deauthorizing = amount; + uint96 deauthorizingTo = authorization.authorized - amount; + emit AuthorizationDecreaseRequested( + stakingProvider, + application, + authorization.authorized, + deauthorizingTo + ); + IApplication(application).authorizationDecreaseRequested( + stakingProvider, + authorization.authorized, + deauthorizingTo + ); } /// @notice Returns the maximum application authorization @@ -745,21 +691,6 @@ contract TokenStaking is Initializable, IStaking, Checkpoints { } } - /// @notice Returns available amount to instantly deauthorize. - function getAvailableOptOutAmount(address stakingProvider) - public - view - returns (uint96 availableToOptOut) - { - StakingProviderInfo storage stakingProviderStruct = stakingProviders[ - stakingProvider - ]; - (availableToOptOut, ) = getAvailableOptOutAmount( - stakingProvider, - stakingProviderStruct - ); - } - /// @notice Delegate voting power from the stake associated to the /// `stakingProvider` to a `delegatee` address. Caller must be the owner /// of this stake. @@ -938,23 +869,6 @@ contract TokenStaking is Initializable, IStaking, Checkpoints { require(deauthorized > 0, "Nothing to deauthorize"); } - function getAvailableOptOutAmount( - address stakingProvider, - StakingProviderInfo storage stakingProviderStruct - ) - internal - view - returns (uint96 availableToOptOut, uint96 maxAuthorization) - { - maxAuthorization = getMaxAuthorization(stakingProvider); - uint96 optOutAmount = stakingProviderStruct.optOutAmount.toUint96(); - if (maxAuthorization < optOutAmount) { - availableToOptOut = 0; - } else { - availableToOptOut = (maxAuthorization - optOutAmount) / 2; - } - } - // slither-disable-next-line dead-code function skipApplication(address application) internal diff --git a/test/staking/TokenStaking.test.js b/test/staking/TokenStaking.test.js index fe0f2b6d..91615fd6 100644 --- a/test/staking/TokenStaking.test.js +++ b/test/staking/TokenStaking.test.js @@ -111,6 +111,228 @@ describe("TokenStaking", () => { }) }) + describe("requestAuthorizationDecrease", () => { + context("when caller is not authorizer", () => { + it("should revert", async () => { + const amount = initialStakerBalance + await expect( + tokenStaking + .connect(staker) + ["requestAuthorizationDecrease(address,address,uint96)"]( + stakingProvider.address, + application1Mock.address, + amount + ) + ).to.be.revertedWith("Not authorizer") + }) + }) + + context( + "when caller is authorizer of staking provider with T stake", + () => { + const amount = initialStakerBalance + + beforeEach(async () => { + await tToken.connect(staker).approve(tokenStaking.address, amount) + await tokenStaking + .connect(staker) + .stake( + stakingProvider.address, + beneficiary.address, + authorizer.address, + amount + ) + await tokenStaking + .connect(deployer) + .approveApplication(application1Mock.address) + await tokenStaking + .connect(authorizer) + .increaseAuthorization( + stakingProvider.address, + application1Mock.address, + amount + ) + }) + + context("when application was paused", () => { + it("should revert", async () => { + const amount = initialStakerBalance + await tokenStaking + .connect(deployer) + .setPanicButton(application1Mock.address, panicButton.address) + await tokenStaking + .connect(panicButton) + .pauseApplication(application1Mock.address) + await expect( + tokenStaking + .connect(authorizer) + ["requestAuthorizationDecrease(address,address,uint96)"]( + stakingProvider.address, + application1Mock.address, + amount + ) + ).to.be.revertedWith("Application is not approved") + }) + }) + + context("when application is disabled", () => { + it("should revert", async () => { + await tokenStaking + .connect(deployer) + .disableApplication(application1Mock.address) + await expect( + tokenStaking + .connect(authorizer) + ["requestAuthorizationDecrease(address,address,uint96)"]( + stakingProvider.address, + application1Mock.address, + 0 + ) + ).to.be.revertedWith("Application is not approved") + }) + }) + + context("when amount to decrease is zero", () => { + it("should revert", async () => { + await expect( + tokenStaking + .connect(authorizer) + ["requestAuthorizationDecrease(address,address,uint96)"]( + stakingProvider.address, + application1Mock.address, + 0 + ) + ).to.be.revertedWith("Parameters must be specified") + }) + }) + + context("when amount to decrease is more than authorized", () => { + it("should revert", async () => { + await expect( + tokenStaking + .connect(authorizer) + ["requestAuthorizationDecrease(address,address,uint96)"]( + stakingProvider.address, + application1Mock.address, + amount.add(1) + ) + ).to.be.revertedWith("Amount exceeds authorized") + }) + }) + + context("when amount to decrease is less than authorized", () => { + const amountToDecrease = amount.div(3) + const expectedFromAmount = amount + const expectedToAmount = amount.sub(amountToDecrease) + let tx + + beforeEach(async () => { + tx = await tokenStaking + .connect(authorizer) + ["requestAuthorizationDecrease(address,address,uint96)"]( + stakingProvider.address, + application1Mock.address, + amountToDecrease + ) + }) + + it("should keep authorized amount unchanged", async () => { + expect( + await tokenStaking.authorizedStake( + stakingProvider.address, + application1Mock.address + ) + ).to.equal(amount) + }) + + it("should send request to application", async () => { + await assertApplicationStakingProviders( + application1Mock, + stakingProvider.address, + amount, + expectedToAmount + ) + }) + + it("should emit AuthorizationDecreaseRequested", async () => { + await expect(tx) + .to.emit(tokenStaking, "AuthorizationDecreaseRequested") + .withArgs( + stakingProvider.address, + application1Mock.address, + expectedFromAmount, + expectedToAmount + ) + }) + }) + + context("when decrease requested twice", () => { + const expectedFromAmount = amount + const amountToDecrease1 = amount.div(3) + const expectedToAmount1 = amount.sub(amountToDecrease1) + const amountToDecrease2 = amount.div(5) + const expectedToAmount2 = amount.sub(amountToDecrease2) + let tx1 + let tx2 + + beforeEach(async () => { + tx1 = await tokenStaking + .connect(authorizer) + ["requestAuthorizationDecrease(address,address,uint96)"]( + stakingProvider.address, + application1Mock.address, + amountToDecrease1 + ) + tx2 = await tokenStaking + .connect(authorizer) + ["requestAuthorizationDecrease(address,address,uint96)"]( + stakingProvider.address, + application1Mock.address, + amountToDecrease2 + ) + }) + + it("should keep authorized amount unchanged", async () => { + expect( + await tokenStaking.authorizedStake( + stakingProvider.address, + application1Mock.address + ) + ).to.equal(amount) + }) + + it("should send request to application with last amount", async () => { + await assertApplicationStakingProviders( + application1Mock, + stakingProvider.address, + amount, + expectedToAmount2 + ) + }) + + it("should emit AuthorizationDecreaseRequested twice", async () => { + await expect(tx1) + .to.emit(tokenStaking, "AuthorizationDecreaseRequested") + .withArgs( + stakingProvider.address, + application1Mock.address, + expectedFromAmount, + expectedToAmount1 + ) + await expect(tx2) + .to.emit(tokenStaking, "AuthorizationDecreaseRequested") + .withArgs( + stakingProvider.address, + application1Mock.address, + expectedFromAmount, + expectedToAmount2 + ) + }) + }) + } + ) + }) + describe("approveAuthorizationDecrease", () => { const amount = initialStakerBalance @@ -513,867 +735,6 @@ describe("TokenStaking", () => { }) }) - describe("forceAuthorizationCap", () => { - const maxStake = to1e18("15000000") // 15m - const amount = maxStake.mul(2) - - beforeEach(async () => { - await tToken.connect(deployer).transfer(staker.address, amount) - - await tokenStaking - .connect(deployer) - .approveApplication(application1Mock.address) - await tToken.connect(staker).approve(tokenStaking.address, amount) - await tokenStaking - .connect(staker) - .stake( - stakingProvider.address, - beneficiary.address, - authorizer.address, - amount - ) - }) - - context("when stake is less than 15m", () => { - it("should revert", async () => { - await tokenStaking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - application1Mock.address, - maxStake - ) - await expect( - tokenStaking - .connect(authorizer) - ["forceAuthorizationCap(address)"](stakingProvider.address) - ).to.be.revertedWith("Nothing to deauthorize") - }) - }) - - context("when authorization is more than 15m for one application", () => { - let tx - const amount2 = maxStake.div(3) - - beforeEach(async () => { - await tokenStaking - .connect(deployer) - .approveApplication(application2Mock.address) - - await tokenStaking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - application1Mock.address, - amount - ) - - await tokenStaking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - application2Mock.address, - amount2 - ) - - tx = await tokenStaking - .connect(deployer) - ["forceAuthorizationCap(address)"](stakingProvider.address) - }) - - it("should set authorized amount to max", async () => { - expect( - await tokenStaking.authorizedStake( - stakingProvider.address, - application1Mock.address - ) - ).to.equal(maxStake) - expect( - await tokenStaking.authorizedStake( - stakingProvider.address, - application2Mock.address - ) - ).to.equal(amount2) - }) - - it("should emit AuthorizationDecreaseApproved", async () => { - await expect(tx) - .to.emit(tokenStaking, "AuthorizationDecreaseApproved") - .withArgs( - stakingProvider.address, - application1Mock.address, - amount, - maxStake - ) - }) - }) - - context("when previous deauthorization is in process", () => { - let tx - const amountToDecrease = amount.div(20) - const amountToDecrease2 = maxStake.add(amountToDecrease) - - beforeEach(async () => { - await tokenStaking - .connect(deployer) - .approveApplication(application2Mock.address) - - await tokenStaking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - application1Mock.address, - amount - ) - - await tokenStaking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - application2Mock.address, - amount - ) - - await tokenStaking - .connect(authorizer) - ["legacyRequestAuthorizationDecrease(address,address,uint96)"]( - stakingProvider.address, - application1Mock.address, - amountToDecrease - ) - await tokenStaking - .connect(authorizer) - ["legacyRequestAuthorizationDecrease(address,address,uint96)"]( - stakingProvider.address, - application2Mock.address, - amountToDecrease2 - ) - - tx = await tokenStaking - .connect(deployer) - ["forceAuthorizationCap(address)"](stakingProvider.address) - }) - - it("should set authorized amount to max", async () => { - expect( - await tokenStaking.authorizedStake( - stakingProvider.address, - application1Mock.address - ) - ).to.equal(maxStake) - expect( - await tokenStaking.authorizedStake( - stakingProvider.address, - application2Mock.address - ) - ).to.equal(maxStake) - }) - - it("should send request to application with last amount", async () => { - expect( - await tokenStaking.getDeauthorizingAmount( - stakingProvider.address, - application1Mock.address - ) - ).to.equal(0) - expect( - await tokenStaking.getDeauthorizingAmount( - stakingProvider.address, - application2Mock.address - ) - ).to.equal(amountToDecrease) - }) - - it("should emit AuthorizationDecreaseApproved", async () => { - await expect(tx) - .to.emit(tokenStaking, "AuthorizationDecreaseApproved") - .withArgs( - stakingProvider.address, - application1Mock.address, - amount, - maxStake - ) - }) - }) - - context("when sending transaction for multiple staking providers", () => { - let tx - - beforeEach(async () => { - await tToken.connect(deployer).transfer(otherStaker.address, amount) - - await tToken.connect(otherStaker).approve(tokenStaking.address, amount) - await tokenStaking - .connect(otherStaker) - .stake( - otherStaker.address, - otherStaker.address, - otherStaker.address, - amount - ) - - await tokenStaking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - application1Mock.address, - amount - ) - - await tokenStaking - .connect(otherStaker) - .increaseAuthorization( - otherStaker.address, - application1Mock.address, - amount - ) - - tx = await tokenStaking - .connect(deployer) - ["forceAuthorizationCap(address[])"]([ - stakingProvider.address, - otherStaker.address, - ]) - }) - - it("should set authorized amount to max", async () => { - expect( - await tokenStaking.authorizedStake( - stakingProvider.address, - application1Mock.address - ) - ).to.equal(maxStake) - expect( - await tokenStaking.authorizedStake( - otherStaker.address, - application1Mock.address - ) - ).to.equal(maxStake) - }) - - it("should emit AuthorizationDecreaseApproved", async () => { - await expect(tx) - .to.emit(tokenStaking, "AuthorizationDecreaseApproved") - .withArgs( - stakingProvider.address, - application1Mock.address, - amount, - maxStake - ) - await expect(tx) - .to.emit(tokenStaking, "AuthorizationDecreaseApproved") - .withArgs( - otherStaker.address, - application1Mock.address, - amount, - maxStake - ) - }) - }) - }) - - describe("optOutDecreaseAuthorization", () => { - const maxStake = to1e18("15000000") // 15m - const amount = maxStake.mul(2) - - beforeEach(async () => { - await tToken.connect(deployer).transfer(staker.address, amount) - - await tokenStaking - .connect(deployer) - .approveApplication(application1Mock.address) - await tToken.connect(staker).approve(tokenStaking.address, amount) - await tokenStaking - .connect(staker) - .stake( - stakingProvider.address, - beneficiary.address, - authorizer.address, - amount - ) - }) - - context("when staking provider has no stake", () => { - it("should revert", async () => { - await expect( - tokenStaking.optOutDecreaseAuthorization(stakingProvider.address, 0) - ).to.be.revertedWith("Not authorizer") - }) - }) - - context("when amount to decrease is zero", () => { - it("should revert", async () => { - await expect( - tokenStaking - .connect(authorizer) - .optOutDecreaseAuthorization(stakingProvider.address, 0) - ).to.be.revertedWith("Parameters must be specified") - }) - }) - - context("when request too big amount for opt-out", () => { - const amount2 = maxStake.div(2) - const amountToOptOut = amount2.div(2) - - it("should revert", async () => { - await expect( - tokenStaking - .connect(authorizer) - .optOutDecreaseAuthorization(stakingProvider.address, 1) - ).to.be.revertedWith("Opt-out amount too high") - - await tokenStaking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - application1Mock.address, - amount2 - ) - await expect( - tokenStaking - .connect(authorizer) - .optOutDecreaseAuthorization( - stakingProvider.address, - amountToOptOut.add(1) - ) - ).to.be.revertedWith("Opt-out amount too high") - - await tokenStaking - .connect(authorizer) - .optOutDecreaseAuthorization(stakingProvider.address, amountToOptOut) - await expect( - tokenStaking - .connect(authorizer) - .optOutDecreaseAuthorization(stakingProvider.address, 1) - ).to.be.revertedWith("Opt-out amount too high") - }) - }) - - context("when authorization is more than 15m for one application", () => { - let tx - const amount2 = maxStake.sub(1) - const amountToOptOut = maxStake.div(4) - const expectedAmount = maxStake.sub(amountToOptOut) - - beforeEach(async () => { - await tokenStaking - .connect(deployer) - .approveApplication(application2Mock.address) - - await tokenStaking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - application1Mock.address, - amount - ) - - await tokenStaking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - application2Mock.address, - amount2 - ) - - tx = await tokenStaking - .connect(authorizer) - .optOutDecreaseAuthorization(stakingProvider.address, amountToOptOut) - }) - - it("should update authorized amount", async () => { - expect( - await tokenStaking.authorizedStake( - stakingProvider.address, - application1Mock.address - ) - ).to.equal(expectedAmount) - expect( - await tokenStaking.authorizedStake( - stakingProvider.address, - application2Mock.address - ) - ).to.equal(expectedAmount) - }) - - it("should update available opt-out amount", async () => { - expect( - await tokenStaking.getAvailableOptOutAmount(stakingProvider.address) - ).to.equal(maxStake.div(2).sub(amountToOptOut)) - }) - - it("should emit AuthorizationDecreaseApproved", async () => { - await expect(tx) - .to.emit(tokenStaking, "AuthorizationDecreaseApproved") - .withArgs( - stakingProvider.address, - application1Mock.address, - amount, - maxStake - ) - await expect(tx) - .to.emit(tokenStaking, "AuthorizationDecreaseApproved") - .withArgs( - stakingProvider.address, - application1Mock.address, - maxStake, - expectedAmount - ) - await expect(tx) - .to.emit(tokenStaking, "AuthorizationDecreaseApproved") - .withArgs( - stakingProvider.address, - application2Mock.address, - amount2, - expectedAmount - ) - }) - - context("when use all opt-out amount and decrease after", () => { - beforeEach(async () => { - await tokenStaking - .connect(authorizer) - .optOutDecreaseAuthorization( - stakingProvider.address, - maxStake.div(2).sub(amountToOptOut) - ) - - await tokenStaking - .connect(authorizer) - ["legacyRequestAuthorizationDecrease(address,address,uint96)"]( - stakingProvider.address, - application1Mock.address, - maxStake.div(4) - ) - await tokenStaking - .connect(authorizer) - ["legacyRequestAuthorizationDecrease(address,address,uint96)"]( - stakingProvider.address, - application2Mock.address, - maxStake.div(4) - ) - await application1Mock.approveAuthorizationDecrease( - stakingProvider.address - ) - await application2Mock.approveAuthorizationDecrease( - stakingProvider.address - ) - }) - - it("should update available opt-out amount", async () => { - expect( - await tokenStaking.getAvailableOptOutAmount(stakingProvider.address) - ).to.equal(0) - }) - - it("should revert when calling for more opt-out", async () => { - await expect( - tokenStaking - .connect(authorizer) - .optOutDecreaseAuthorization(stakingProvider.address, 1) - ).to.be.revertedWith("Opt-out amount too high") - }) - }) - }) - - context("when calling transaction multiple times", () => { - let tx - const amountToDecrease = amount.div(20) - const amountToOptOut1 = maxStake.div(3) - const amountToOptOut2 = maxStake.div(6) - const expectedAmount = maxStake.sub(amountToOptOut1).sub(amountToOptOut2) - - beforeEach(async () => { - await tokenStaking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - application1Mock.address, - amount - ) - - await tokenStaking - .connect(authorizer) - ["legacyRequestAuthorizationDecrease(address,address,uint96)"]( - stakingProvider.address, - application1Mock.address, - amountToDecrease - ) - - await tokenStaking - .connect(deployer) - ["forceAuthorizationCap(address)"](stakingProvider.address) - - await tokenStaking - .connect(authorizer) - .optOutDecreaseAuthorization(stakingProvider.address, amountToOptOut1) - tx = await tokenStaking - .connect(authorizer) - .optOutDecreaseAuthorization(stakingProvider.address, amountToOptOut2) - }) - - it("should update authorized amount", async () => { - expect( - await tokenStaking.authorizedStake( - stakingProvider.address, - application1Mock.address - ) - ).to.equal(expectedAmount) - }) - - it("should update available opt-out amount", async () => { - expect( - await tokenStaking.getAvailableOptOutAmount(stakingProvider.address) - ).to.equal(maxStake.div(2).sub(amountToOptOut1).sub(amountToOptOut2)) - }) - - it("should cancel deauthorization amount", async () => { - expect( - await tokenStaking.getDeauthorizingAmount( - stakingProvider.address, - application2Mock.address - ) - ).to.equal(0) - }) - - it("should emit AuthorizationDecreaseApproved", async () => { - await expect(tx) - .to.emit(tokenStaking, "AuthorizationDecreaseApproved") - .withArgs( - stakingProvider.address, - application1Mock.address, - maxStake.sub(amountToOptOut1), - maxStake.sub(amountToOptOut1).sub(amountToOptOut2) - ) - }) - }) - }) - - describe("forceBetaStakerDecreaseAuthorization", () => { - const amount = initialStakerBalance - - beforeEach(async () => { - await tToken.connect(deployer).transfer(staker.address, amount.mul(10)) - - await tokenStaking - .connect(deployer) - .approveApplication(application1Mock.address) - await tToken.connect(staker).approve(tokenStaking.address, amount.mul(10)) - await tokenStaking - .connect(staker) - .stake( - stakingProvider.address, - beneficiary.address, - authorizer.address, - amount - ) - }) - - context("when caller is not the governance", () => { - it("should revert", async () => { - await expect( - tokenStaking - .connect(stakingProvider) - ["forceBetaStakerDecreaseAuthorization(address)"]( - stakingProvider.address - ) - ).to.be.revertedWith("Caller is not the governance") - }) - }) - - context("when nothing was authorized", () => { - it("should revert", async () => { - await expect( - tokenStaking - .connect(deployer) - ["forceBetaStakerDecreaseAuthorization(address)"]( - stakingProvider.address - ) - ).to.be.revertedWith("Nothing was authorized") - }) - }) - - context("when deauthorizing one beta staker", () => { - let tx - const amount2 = amount.div(3) - - beforeEach(async () => { - await tokenStaking - .connect(deployer) - .approveApplication(application2Mock.address) - - await tokenStaking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - application1Mock.address, - amount - ) - - await tokenStaking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - application2Mock.address, - amount2 - ) - - tx = await tokenStaking - .connect(deployer) - ["forceBetaStakerDecreaseAuthorization(address)"]( - stakingProvider.address - ) - }) - - it("should set authorized amount to 0", async () => { - expect( - await tokenStaking.authorizedStake( - stakingProvider.address, - application1Mock.address - ) - ).to.equal(0) - expect( - await tokenStaking.authorizedStake( - stakingProvider.address, - application2Mock.address - ) - ).to.equal(0) - }) - - it("should not send request to the applications", async () => { - await assertApplicationStakingProviders( - application1Mock, - stakingProvider.address, - amount, - 0 - ) - await assertApplicationStakingProviders( - application2Mock, - stakingProvider.address, - amount2, - 0 - ) - }) - - it("should emit AuthorizationDecreaseApproved", async () => { - await expect(tx) - .to.emit(tokenStaking, "AuthorizationDecreaseApproved") - .withArgs( - stakingProvider.address, - application1Mock.address, - amount, - 0 - ) - await expect(tx) - .to.emit(tokenStaking, "AuthorizationDecreaseApproved") - .withArgs( - stakingProvider.address, - application2Mock.address, - amount2, - 0 - ) - }) - }) - - context("when previous deauthorization is in process", () => { - let tx - const amountToDecrease = amount.div(20) - const amountToDecrease2 = amountToDecrease.mul(2) - - beforeEach(async () => { - await tokenStaking - .connect(deployer) - .approveApplication(application2Mock.address) - - await tokenStaking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - application1Mock.address, - amount - ) - - await tokenStaking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - application2Mock.address, - amount - ) - - await tokenStaking - .connect(authorizer) - ["legacyRequestAuthorizationDecrease(address,address,uint96)"]( - stakingProvider.address, - application1Mock.address, - amountToDecrease - ) - await tokenStaking - .connect(authorizer) - ["legacyRequestAuthorizationDecrease(address,address,uint96)"]( - stakingProvider.address, - application2Mock.address, - amountToDecrease2 - ) - - tx = await tokenStaking - .connect(deployer) - ["forceBetaStakerDecreaseAuthorization(address)"]( - stakingProvider.address - ) - }) - - it("should set authorized amount to 0", async () => { - expect( - await tokenStaking.authorizedStake( - stakingProvider.address, - application1Mock.address - ) - ).to.equal(0) - expect( - await tokenStaking.authorizedStake( - stakingProvider.address, - application2Mock.address - ) - ).to.equal(0) - }) - - it("should not send request to the applications", async () => { - await assertApplicationStakingProviders( - application1Mock, - stakingProvider.address, - amount, - amount.sub(amountToDecrease) - ) - await assertApplicationStakingProviders( - application2Mock, - stakingProvider.address, - amount, - amount.sub(amountToDecrease2) - ) - }) - - it("should set deauthorizing amount to 0", async () => { - expect( - await tokenStaking.getDeauthorizingAmount( - stakingProvider.address, - application1Mock.address - ) - ).to.equal(0) - expect( - await tokenStaking.getDeauthorizingAmount( - stakingProvider.address, - application2Mock.address - ) - ).to.equal(0) - }) - - it("should emit AuthorizationDecreaseApproved", async () => { - await expect(tx) - .to.emit(tokenStaking, "AuthorizationDecreaseApproved") - .withArgs( - stakingProvider.address, - application1Mock.address, - amount, - 0 - ) - await expect(tx) - .to.emit(tokenStaking, "AuthorizationDecreaseApproved") - .withArgs( - stakingProvider.address, - application2Mock.address, - amount, - 0 - ) - }) - }) - - context("when sending transaction for multiple staking providers", () => { - let tx - - beforeEach(async () => { - await tToken.connect(deployer).transfer(otherStaker.address, amount) - - await tToken.connect(otherStaker).approve(tokenStaking.address, amount) - await tokenStaking - .connect(otherStaker) - .stake( - otherStaker.address, - otherStaker.address, - otherStaker.address, - amount - ) - - await tokenStaking - .connect(authorizer) - .increaseAuthorization( - stakingProvider.address, - application1Mock.address, - amount - ) - - await tokenStaking - .connect(otherStaker) - .increaseAuthorization( - otherStaker.address, - application1Mock.address, - amount - ) - - tx = await tokenStaking - .connect(deployer) - ["forceBetaStakerDecreaseAuthorization(address[])"]([ - stakingProvider.address, - otherStaker.address, - ]) - }) - - it("should set authorized amount to 0", async () => { - expect( - await tokenStaking.authorizedStake( - stakingProvider.address, - application1Mock.address - ) - ).to.equal(0) - expect( - await tokenStaking.authorizedStake( - otherStaker.address, - application1Mock.address - ) - ).to.equal(0) - }) - - it("should not send request to the application", async () => { - await assertApplicationStakingProviders( - application1Mock, - stakingProvider.address, - amount, - 0 - ) - await assertApplicationStakingProviders( - application1Mock, - otherStaker.address, - amount, - 0 - ) - }) - - it("should emit AuthorizationDecreaseApproved", async () => { - await expect(tx) - .to.emit(tokenStaking, "AuthorizationDecreaseApproved") - .withArgs( - stakingProvider.address, - application1Mock.address, - amount, - 0 - ) - await expect(tx) - .to.emit(tokenStaking, "AuthorizationDecreaseApproved") - .withArgs(otherStaker.address, application1Mock.address, amount, 0) - }) - }) - }) - describe("pauseApplication", () => { beforeEach(async () => { await tokenStaking