forked from axieinfinity/ronin-dpos-contracts
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8a37936
commit 85635da
Showing
7 changed files
with
314 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
31 changes: 31 additions & 0 deletions
31
test/bridge/integration/pause-enforcer/set-config/accessControl.PauseEnforcer.t.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.19; | ||
|
||
import "../../BaseIntegration.t.sol"; | ||
|
||
contract AccessControl_PauseEnforcer_Test is BaseIntegration_Test { | ||
function setUp() public virtual override { | ||
super.setUp(); | ||
_config.switchTo(Network.RoninLocal.key()); | ||
} | ||
|
||
function test_changeAdmin_OfPauseEnforcer() public { | ||
address newEnforcerAdmin = makeAddr("new-enforcer-admin"); | ||
|
||
vm.prank(_param.roninPauseEnforcer.admin); | ||
_roninPauseEnforcer.grantRole(0x0, newEnforcerAdmin); | ||
|
||
assertEq(_roninPauseEnforcer.hasRole(0x0, newEnforcerAdmin), true); | ||
} | ||
|
||
function test_renounceAdminRole_PreviousAdmin() public { | ||
test_changeAdmin_OfPauseEnforcer(); | ||
|
||
assertEq(_roninPauseEnforcer.hasRole(0x0, _param.roninPauseEnforcer.admin), true); | ||
|
||
vm.prank(_param.roninPauseEnforcer.admin); | ||
_roninPauseEnforcer.renounceRole(0x0, _param.roninPauseEnforcer.admin); | ||
|
||
assertEq(_roninPauseEnforcer.hasRole(0x0, _param.roninPauseEnforcer.admin), false); | ||
} | ||
} |
88 changes: 88 additions & 0 deletions
88
test/bridge/integration/pause-enforcer/set-config/emergencyAction.PauseEnforcer.t.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.19; | ||
|
||
import { Transfer } from "@ronin/contracts/libraries/Transfer.sol"; | ||
import { GatewayV3 } from "@ronin/contracts/extensions/GatewayV3.sol"; | ||
import "../../BaseIntegration.t.sol"; | ||
|
||
contract EmergencyAction_PauseEnforcer_Test is BaseIntegration_Test { | ||
error ErrTargetIsNotOnPaused(); | ||
|
||
function setUp() public virtual override { | ||
super.setUp(); | ||
} | ||
|
||
// Should be able to emergency pause | ||
function test_EmergencyPause_RoninGatewayV3() public { | ||
_config.switchTo(Network.RoninLocal.key()); | ||
vm.prank(_param.roninPauseEnforcer.sentries[0]); | ||
_roninPauseEnforcer.triggerPause(); | ||
|
||
assertEq(_roninPauseEnforcer.emergency(), true); | ||
assertEq(_roninGatewayV3.paused(), true); | ||
} | ||
|
||
// Should the gateway cannot interacted when on pause | ||
function test_RevertWhen_InteractWithGateway_AfterPause() public { | ||
test_EmergencyPause_RoninGatewayV3(); | ||
Transfer.Receipt memory receipt = Transfer.Receipt({ | ||
id: 0, | ||
kind: Transfer.Kind.Deposit, | ||
ronin: Token.Owner({ addr: makeAddr("recipient"), tokenAddr: address(_roninWeth), chainId: _param.test.roninChainId }), | ||
mainchain: Token.Owner({ | ||
addr: makeAddr("requester"), | ||
tokenAddr: address(_mainchainWeth), | ||
chainId: _param.test.mainchainChainId | ||
}), | ||
info: Token.Info({ erc: Token.Standard.ERC20, id: 0, quantity: 100 }) | ||
}); | ||
|
||
vm.expectRevert("Pausable: paused"); | ||
|
||
_roninGatewayV3.depositFor(receipt); | ||
} | ||
|
||
// Should not be able to emergency pause for a second time | ||
function test_RevertWhen_PauseAgain() public { | ||
test_EmergencyPause_RoninGatewayV3(); | ||
|
||
vm.expectRevert(ErrTargetIsNotOnPaused.selector); | ||
|
||
vm.prank(_param.roninPauseEnforcer.sentries[0]); | ||
_roninPauseEnforcer.triggerPause(); | ||
} | ||
|
||
// Should be able to emergency unpause | ||
function test_EmergencyUnpause_RoninGatewayV3() public { | ||
test_EmergencyPause_RoninGatewayV3(); | ||
|
||
vm.prank(_param.roninPauseEnforcer.sentries[0]); | ||
_roninPauseEnforcer.triggerUnpause(); | ||
|
||
assertEq(_roninPauseEnforcer.emergency(), false); | ||
assertEq(_roninGatewayV3.paused(), false); | ||
} | ||
|
||
// Should the gateway can be interacted after unpause | ||
function test_InteractWithGateway_AfterUnpause() public { | ||
test_EmergencyUnpause_RoninGatewayV3(); | ||
Transfer.Receipt memory receipt = Transfer.Receipt({ | ||
id: 0, | ||
kind: Transfer.Kind.Deposit, | ||
ronin: Token.Owner({ addr: makeAddr("recipient"), tokenAddr: address(_roninWeth), chainId: _param.test.roninChainId }), | ||
mainchain: Token.Owner({ | ||
addr: makeAddr("requester"), | ||
tokenAddr: address(_mainchainWeth), | ||
chainId: _param.test.mainchainChainId | ||
}), | ||
info: Token.Info({ erc: Token.Standard.ERC20, id: 0, quantity: 100 }) | ||
}); | ||
|
||
uint256 numOperatorsForVoteExecuted = | ||
_param.roninBridgeManager.bridgeOperators.length * _param.roninBridgeManager.num / _param.roninBridgeManager.denom; | ||
for (uint256 i; i < numOperatorsForVoteExecuted; i++) { | ||
vm.prank(_param.roninBridgeManager.bridgeOperators[i]); | ||
_roninGatewayV3.depositFor(receipt); | ||
} | ||
} | ||
} |
61 changes: 61 additions & 0 deletions
61
test/bridge/integration/pause-enforcer/set-config/normalPause.GatewayV3.t.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.19; | ||
|
||
import { Transfer } from "@ronin/contracts/libraries/Transfer.sol"; | ||
import { GatewayV3 } from "@ronin/contracts/extensions/GatewayV3.sol"; | ||
import "../../BaseIntegration.t.sol"; | ||
|
||
contract NormalPause_GatewayV3_Test is BaseIntegration_Test { | ||
error ErrNotOnEmergencyPause(); | ||
error ErrTargetIsNotOnPaused(); | ||
|
||
function setUp() public virtual override { | ||
super.setUp(); | ||
_config.switchTo(Network.RoninLocal.key()); | ||
} | ||
|
||
// Should gateway admin can pause the gateway through voting | ||
function test_GovernanceAdmin_PauseGateway_ThroughoutVoting() public { | ||
bytes memory calldata_ = abi.encodeCall(GatewayV3.pause, ()); | ||
_roninProposalUtils.functionDelegateCall(address(_roninGatewayV3), calldata_); | ||
|
||
assertEq(_roninPauseEnforcer.emergency(), false); | ||
assertEq(_roninGatewayV3.paused(), true); | ||
} | ||
|
||
// Should not be able to emergency unpause | ||
function test_RevertWhen_EmergencyUnpause() public { | ||
test_GovernanceAdmin_PauseGateway_ThroughoutVoting(); | ||
|
||
vm.expectRevert(ErrNotOnEmergencyPause.selector); | ||
|
||
vm.prank(_param.roninPauseEnforcer.sentries[0]); | ||
_roninPauseEnforcer.triggerUnpause(); | ||
} | ||
|
||
// Should not be able to override by emergency pause and emergency unpause | ||
function test_RevertWhen_OverrideByEmergencyPauseOrUnPause() public { | ||
test_GovernanceAdmin_PauseGateway_ThroughoutVoting(); | ||
|
||
vm.expectRevert(ErrTargetIsNotOnPaused.selector); | ||
|
||
vm.prank(_param.roninPauseEnforcer.sentries[0]); | ||
_roninPauseEnforcer.triggerPause(); | ||
|
||
vm.expectRevert(ErrNotOnEmergencyPause.selector); | ||
|
||
vm.prank(_param.roninPauseEnforcer.sentries[0]); | ||
_roninPauseEnforcer.triggerUnpause(); | ||
} | ||
|
||
// Should gateway admin can unpause the gateway through voting | ||
function test_GovernanceAdmin_UnPauseGateway_ThroughoutVoting() public { | ||
test_GovernanceAdmin_PauseGateway_ThroughoutVoting(); | ||
|
||
bytes memory calldata_ = abi.encodeCall(GatewayV3.unpause, ()); | ||
_roninProposalUtils.functionDelegateCall(address(_roninGatewayV3), calldata_); | ||
|
||
assertEq(_roninPauseEnforcer.emergency(), false); | ||
assertEq(_roninGatewayV3.paused(), false); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
import { MainchainBridgeManager } from "@ronin/contracts/mainchain/MainchainBridgeManager.sol"; | ||
import "./ProposalUtils.t.sol"; | ||
|
||
contract MainchainBridgeAdminUtils is ProposalUtils { | ||
MainchainBridgeManager _contract; | ||
address _sender; | ||
|
||
constructor(uint256 roninChainId, uint256[] memory signerPKs, MainchainBridgeManager contract_, address sender) | ||
ProposalUtils(roninChainId, signerPKs) | ||
{ | ||
_contract = contract_; | ||
_sender = sender; | ||
} | ||
|
||
function defaultExpiryTimestamp() public view returns (uint256) { | ||
return block.timestamp + 10; | ||
} | ||
|
||
function functionDelegateCall(address to, bytes memory data) public { | ||
Proposal.ProposalDetail memory proposal = this.createProposal({ | ||
expiryTimestamp: this.defaultExpiryTimestamp(), | ||
target: to, | ||
value: 0, | ||
calldata_: abi.encodeWithSignature("functionDelegateCall(bytes)", data), | ||
gasAmount: 2_000_000, | ||
nonce: _contract.round(_roninChainId) + 1 | ||
}); | ||
|
||
SignatureConsumer.Signature[] memory signatures = this.generateSignatures(proposal); | ||
uint256 length = signatures.length; | ||
Ballot.VoteType[] memory supports_ = new Ballot.VoteType[](length); | ||
for (uint256 i; i < length; i++) { | ||
supports_[i] = Ballot.VoteType.For; | ||
} | ||
vm.prank(_sender); | ||
_contract.relayProposal(proposal, supports_, signatures); | ||
} | ||
|
||
function functionDelegateCallGlobal(GlobalProposal.TargetOption target, bytes memory data) public { | ||
GlobalProposal.GlobalProposalDetail memory proposal = this.createGlobalProposal({ | ||
expiryTimestamp: this.defaultExpiryTimestamp(), | ||
targetOption: target, | ||
value: 0, | ||
calldata_: abi.encodeWithSignature("functionDelegateCall(bytes)", data), | ||
gasAmount: 2_000_000, | ||
nonce: _contract.round(0) + 1 | ||
}); | ||
|
||
SignatureConsumer.Signature[] memory signatures = this.generateSignaturesGlobal(proposal); | ||
uint256 length = signatures.length; | ||
Ballot.VoteType[] memory supports_ = new Ballot.VoteType[](length); | ||
for (uint256 i; i < length; i++) { | ||
supports_[i] = Ballot.VoteType.For; | ||
} | ||
vm.prank(_sender); | ||
_contract.relayGlobalProposal(proposal, supports_, signatures); | ||
} | ||
|
||
function functionDelegateCallsGlobal(GlobalProposal.TargetOption[] memory targetOptions, bytes[] memory datas) public { | ||
uint256 length = targetOptions.length; | ||
if (length != datas.length || length == 0) revert("Invalid length"); | ||
|
||
bytes[] memory calldatas = new bytes[](length); | ||
uint256[] memory values = new uint256[](length); | ||
uint256[] memory gasAmounts = new uint256[](length); | ||
for (uint256 i; i < length; i++) { | ||
calldatas[i] = abi.encodeWithSignature("functionDelegateCall(bytes)", datas[i]); | ||
values[i] = 0; | ||
gasAmounts[i] = 2_000_000; | ||
} | ||
|
||
GlobalProposal.GlobalProposalDetail memory proposal = GlobalProposal.GlobalProposalDetail({ | ||
nonce: _contract.round(0) + 1, | ||
expiryTimestamp: this.defaultExpiryTimestamp(), | ||
targetOptions: targetOptions, | ||
values: values, | ||
calldatas: calldatas, | ||
gasAmounts: gasAmounts | ||
}); | ||
|
||
SignatureConsumer.Signature[] memory signatures = this.generateSignaturesGlobal(proposal); | ||
length = signatures.length; | ||
Ballot.VoteType[] memory supports_ = new Ballot.VoteType[](length); | ||
for (uint256 i; i < length; i++) { | ||
supports_[i] = Ballot.VoteType.For; | ||
} | ||
vm.prank(_sender); | ||
_contract.relayGlobalProposal(proposal, supports_, signatures); | ||
} | ||
|
||
function upgradeGlobal(GlobalProposal.TargetOption targetOption, uint256 nonce, bytes memory data) public { | ||
GlobalProposal.GlobalProposalDetail memory proposal = this.createGlobalProposal({ | ||
expiryTimestamp: this.defaultExpiryTimestamp(), | ||
targetOption: targetOption, | ||
value: 0, | ||
calldata_: abi.encodeWithSignature("upgradeTo(bytes)", data), | ||
gasAmount: 2_000_000, | ||
nonce: nonce | ||
}); | ||
|
||
SignatureConsumer.Signature[] memory signatures = this.generateSignaturesGlobal(proposal); | ||
uint256 length = signatures.length; | ||
Ballot.VoteType[] memory supports_ = new Ballot.VoteType[](length); | ||
for (uint256 i; i < length; i++) { | ||
supports_[i] = Ballot.VoteType.For; | ||
} | ||
vm.prank(_sender); | ||
_contract.relayGlobalProposal(proposal, supports_, signatures); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters