diff --git a/contracts/core/UniversalChannelHandler.sol b/contracts/core/UniversalChannelHandler.sol index e233eca5..d1fcbd23 100644 --- a/contracts/core/UniversalChannelHandler.sol +++ b/contracts/core/UniversalChannelHandler.sol @@ -191,6 +191,10 @@ contract UniversalChannelHandler is IbcReceiverBaseUpgradeable, IbcUniversalChan function onChanOpenConfirm(bytes32 channelId) external onlyIbcDispatcher {} + function setDispatcher(IbcDispatcher _dispatcher) external onlyOwner { + dispatcher = _dispatcher; + } + function _connectChannel(bytes32 channelId, string calldata version) internal returns (string memory checkedVersion) diff --git a/contracts/interfaces/IUniversalChannelHandler.sol b/contracts/interfaces/IUniversalChannelHandler.sol index 5df25101..7a1d4c91 100644 --- a/contracts/interfaces/IUniversalChannelHandler.sol +++ b/contracts/interfaces/IUniversalChannelHandler.sol @@ -27,5 +27,7 @@ interface IUniversalChannelHandler is IbcUniversalChannelMW { string calldata counterpartyPortIdentifier ) external; function closeChannel(bytes32 channelId) external; - function connectedChannels(uint256) external view returns (bytes32); + function setDispatcher(IbcDispatcher dispatcher) external; + function dispatcher() external returns (IbcDispatcher dispatcher); + function connectedChannels(uint256) external view returns (bytes32 channel); } diff --git a/contracts/interfaces/IbcReceiverUpgradeable.sol b/contracts/interfaces/IbcReceiverUpgradeable.sol index 0d7a85c0..f748f962 100644 --- a/contracts/interfaces/IbcReceiverUpgradeable.sol +++ b/contracts/interfaces/IbcReceiverUpgradeable.sol @@ -29,6 +29,10 @@ contract IbcReceiverBaseUpgradeable is OwnableUpgradeable { _disableInitializers(); } + /// This function is called for plain Ether transfers, i.e. for every call with empty calldata. + // An empty function body is sufficient to receive packet fee refunds. + receive() external payable {} + /** * @dev initializer function that takes an IbcDispatcher address and grants the IBC_ROLE to the Polymer IBC * Dispatcher. @@ -38,8 +42,4 @@ contract IbcReceiverBaseUpgradeable is OwnableUpgradeable { __Ownable_init(); dispatcher = _dispatcher; } - - /// This function is called for plain Ether transfers, i.e. for every call with empty calldata. - // An empty function body is sufficient to receive packet fee refunds. - receive() external payable {} } diff --git a/test/universal.channel.t.sol b/test/universal.channel.t.sol index 0e020642..37a0e571 100644 --- a/test/universal.channel.t.sol +++ b/test/universal.channel.t.sol @@ -222,6 +222,29 @@ contract UniversalChannelPacketTest is Base, IbcMwEventsEmitter { verifyTimeoutFlow(5, mwBitmap); } + function test_uch_new_dispatcher_set_ok() public { + IUniversalChannelHandler uch = eth1.ucHandlerProxy(); + vm.startPrank(address(eth1)); // Prank eth1 since that address is the owner + (IDispatcher newDispatcher,) = deployDispatcherProxyAndImpl("polyibc.new.", dummyConsStateManager); + assertFalse( + address(uch.dispatcher()) == address(newDispatcher), "new dispatcher in uch test not setup correctly" + ); + uch.setDispatcher(newDispatcher); + assertEq(address(uch.dispatcher()), address(newDispatcher), "new dispatcher not set correctly in uch"); + vm.stopPrank(); + } + + function test_nonOwner_cannot_set_uch_dispatcher() public { + IUniversalChannelHandler uch = eth1.ucHandlerProxy(); + address notOwner = vm.addr(1); + vm.startPrank(notOwner); + (IDispatcher newDispatcher,) = deployDispatcherProxyAndImpl("polyibc.new.", dummyConsStateManager); + + vm.expectRevert("Ownable: caller is not the owner"); + uch.setDispatcher(newDispatcher); + vm.stopPrank(); + } + /** * Test packet flow from chain A to chain B via UniversalChannel MW and optionally other MW that sits on top of * UniversalChannel MW.