Skip to content

Commit

Permalink
test(PauseEnforcer): done test
Browse files Browse the repository at this point in the history
  • Loading branch information
huyhuynh3103 committed Jan 28, 2024
1 parent 8a37936 commit 85635da
Show file tree
Hide file tree
Showing 7 changed files with 314 additions and 25 deletions.
40 changes: 20 additions & 20 deletions test/bridge/integration/BaseIntegration.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ import { AXSDeploy } from "@ronin/script/contracts/token/AXSDeploy.s.sol";
import { SLPDeploy } from "@ronin/script/contracts/token/SLPDeploy.s.sol";
import { USDCDeploy } from "@ronin/script/contracts/token/USDCDeploy.s.sol";

import { ProposalUtils } from "test/helpers/ProposalUtils.t.sol";
import { RoninBridgeAdminUtils } from "test/helpers/RoninBridgeAdminUtils.t.sol";
import { MainchainBridgeAdminUtils } from "test/helpers/MainchainBridgeAdminUtils.t.sol";

contract BaseIntegration_Test is Base_Test {
IGeneralConfig _config;
Expand Down Expand Up @@ -84,7 +84,7 @@ contract BaseIntegration_Test is Base_Test {
MockValidatorContract_OnlyTiming_ForHardhatTest _validatorSet;

RoninBridgeAdminUtils _roninProposalUtils;
ProposalUtils _mainchainProposalUtils;
MainchainBridgeAdminUtils _mainchainProposalUtils;

function setUp() public virtual {
_deployGeneralConfig();
Expand All @@ -100,6 +100,8 @@ contract BaseIntegration_Test is Base_Test {

_configEmergencyPauserForRoninGateway();
_configEmergencyPauserForMainchainGateway();

_configBridgeTrackingForRoninGateway();
}

function _deployContractsOnRonin() internal {
Expand Down Expand Up @@ -141,7 +143,12 @@ contract BaseIntegration_Test is Base_Test {
_mainchainUsdc = new USDCDeploy().run();

_param = ISharedArgument(LibSharedAddress.CONFIG).sharedArguments();
_mainchainProposalUtils = new ProposalUtils(_param.test.roninChainId, _param.test.governorPKs);
_mainchainProposalUtils = new MainchainBridgeAdminUtils(
_param.test.roninChainId,
_param.test.governorPKs,
_mainchainBridgeManager,
_param.mainchainBridgeManager.governors[0]
);
}

function _initializeRonin() internal {
Expand Down Expand Up @@ -528,24 +535,17 @@ contract BaseIntegration_Test is Base_Test {
_config.switchTo(Network.EthLocal.key());

bytes memory calldata_ = abi.encodeCall(GatewayV3.setEmergencyPauser, (address(_mainchainPauseEnforcer)));
Proposal.ProposalDetail memory proposal = _mainchainProposalUtils.createProposal({
expiryTimestamp: block.timestamp + 1 minutes,
target: address(_mainchainGatewayV3),
value: 0,
calldata_: calldata_,
gasAmount: 1_000_000,
nonce: _mainchainBridgeManager.round(_param.test.mainchainChainId) + 1
});

SignatureConsumer.Signature[] memory signatures = _mainchainProposalUtils.generateSignatures(proposal);

Ballot.VoteType[] memory voteTypes = new Ballot.VoteType[](signatures.length);
for (uint256 i; i < signatures.length; i++) {
voteTypes[i] = Ballot.VoteType.For;
}
_mainchainProposalUtils.functionDelegateCall(address(_mainchainGatewayV3), calldata_);
}

vm.prank(_param.mainchainBridgeManager.governors[0]);
_mainchainBridgeManager.relayProposal(proposal, voteTypes, signatures);
function _configBridgeTrackingForRoninGateway() internal {
_config.switchTo(Network.RoninLocal.key());

bytes memory calldata_ =
abi.encodeCall(IHasContracts.setContract, (ContractType.BRIDGE_TRACKING, address(_bridgeTracking)));
_roninProposalUtils.functionDelegateCall(address(_roninGatewayV3), calldata_);

_config.switchTo(Network.EthLocal.key());
}

function _deployGeneralConfig() internal {
Expand Down
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);
}
}
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);
}
}
}
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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ contract DepositVote_RoninGatewayV3_Test is BaseIntegration_Test {
super.setUp();
_config.switchTo(Network.RoninLocal.key());

bytes memory calldata_ =
abi.encodeCall(IHasContracts.setContract, (ContractType.BRIDGE_TRACKING, address(_bridgeTracking)));
_roninProposalUtils.functionDelegateCallGlobal(GlobalProposal.TargetOption.GatewayContract, calldata_);

vm.etch(address(_roninGatewayV3), address(new MockRoninGatewayV3Extended()).code);

Transfer.Receipt memory receipt = Transfer.Receipt({
Expand Down
113 changes: 113 additions & 0 deletions test/helpers/MainchainBridgeAdminUtils.t.sol
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);
}
}
2 changes: 1 addition & 1 deletion test/helpers/ProposalUtils.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ contract ProposalUtils is Utils, Test {
) public view returns (Proposal.ProposalDetail memory proposal) {
proposal = Proposal.ProposalDetail({
nonce: nonce,
chainId: _roninChainId,
chainId: block.chainid,
expiryTimestamp: expiryTimestamp,
targets: wrapAddress(target),
values: wrapUint(value),
Expand Down

0 comments on commit 85635da

Please sign in to comment.