diff --git a/contracts/evmx/plugs/FeesPlug.sol b/contracts/evmx/plugs/FeesPlug.sol index 5c9f6124..b07942c8 100644 --- a/contracts/evmx/plugs/FeesPlug.sol +++ b/contracts/evmx/plugs/FeesPlug.sol @@ -124,6 +124,10 @@ contract FeesPlug is IFeesPlug, PlugBase, AccessControl { _connectSocket(appGatewayId_, socket_, switchboardId_); } + function disconnectSocket() external onlyOwner { + socket__.disconnect(); + } + /** * @notice Rescues funds from the contract if they are locked by mistake. This contract does not * theoretically need this function but it is added for safety. diff --git a/contracts/protocol/Socket.sol b/contracts/protocol/Socket.sol index fb4ec6d5..ad3f97dd 100644 --- a/contracts/protocol/Socket.sol +++ b/contracts/protocol/Socket.sol @@ -20,9 +20,6 @@ contract Socket is SocketUtils { // @notice mapping of payload id to execution status mapping(bytes32 => bytes32) public payloadIdToDigest; - // @notice buffer to account for gas used by current contract execution - uint256 private constant GAS_LIMIT_BUFFER = 105; - //////////////////////////////////////////////////////// ////////////////////// ERRORS ////////////////////////// //////////////////////////////////////////////////////// @@ -53,7 +50,9 @@ contract Socket is SocketUtils { uint32 chainSlug_, address owner_, string memory version_ - ) SocketUtils(chainSlug_, owner_, version_) {} + ) SocketUtils(chainSlug_, owner_, version_) { + gasLimitBuffer = 105; + } /** * @notice Executes a payload that has been delivered by transmitters and authenticated by switchboards @@ -136,7 +135,7 @@ contract Socket is SocketUtils { ) internal returns (bool success, bytes memory returnData) { // check if the gas limit is sufficient // bump by 5% to account for gas used by current contract execution - if (gasleft() < (executeParams_.gasLimit * GAS_LIMIT_BUFFER) / 100) revert LowGasLimit(); + if (gasleft() < (executeParams_.gasLimit * gasLimitBuffer) / 100) revert LowGasLimit(); // NOTE: external un-trusted call bool exceededMaxCopy; @@ -180,10 +179,20 @@ contract Socket is SocketUtils { //////////////////////////////////////////////////////// ////////////////////// Trigger ////////////////////// //////////////////////////////////////////////////////// + + /// @notice To trigger to a connected remote chain. Should only be called by a plug. + function triggerAppGateway(bytes calldata data_) external payable returns (bytes32 triggerId) { + triggerId = _triggerAppGateway(msg.sender, msg.value, data_); + } + /** * @notice To trigger to a connected remote chain. Should only be called by a plug. */ - function _triggerAppGateway(address plug_) internal returns (bytes32 triggerId) { + function _triggerAppGateway( + address plug_, + uint256 value_, + bytes calldata data_ + ) internal returns (bytes32 triggerId) { PlugConfigEvm memory plugConfig = _plugConfigs[plug_]; // if no sibling plug is found for the given chain slug, revert @@ -191,13 +200,16 @@ contract Socket is SocketUtils { if (isValidSwitchboard[plugConfig.switchboardId] != SwitchboardStatus.REGISTERED) revert InvalidSwitchboard(); - bytes memory plugOverrides = IPlug(msg.sender).overrides(); + bytes memory plugOverrides = IPlug(plug_).overrides(); triggerId = _encodeTriggerId(); // todo: need gas limit? - ISwitchboard(switchboardAddresses[plugConfig.switchboardId]).processTrigger{ - value: msg.value - }(msg.sender, triggerId, msg.data, plugOverrides); + ISwitchboard(switchboardAddresses[plugConfig.switchboardId]).processTrigger{value: value_}( + plug_, + triggerId, + data_, + plugOverrides + ); emit AppGatewayCallRequested( triggerId, @@ -205,7 +217,7 @@ contract Socket is SocketUtils { plugConfig.switchboardId, toBytes32Format(plug_), plugOverrides, - msg.data + data_ ); } @@ -213,11 +225,12 @@ contract Socket is SocketUtils { /// @dev The calldata is passed as-is to the gateways fallback(bytes calldata) external payable returns (bytes memory) { // return the trigger id - return abi.encode(_triggerAppGateway(msg.sender)); + return abi.encode(_triggerAppGateway(msg.sender, msg.value, msg.data)); } /// @notice Receive function that forwards all calls to Socket's callAppGateway receive() external payable { - // todo: handle receive + // todo: need a fn to increase trigger fees + revert("Socket does not accept ETH"); } } diff --git a/contracts/protocol/SocketConfig.sol b/contracts/protocol/SocketConfig.sol index d5fc01d9..2a701b4a 100644 --- a/contracts/protocol/SocketConfig.sol +++ b/contracts/protocol/SocketConfig.sol @@ -39,8 +39,13 @@ abstract contract SocketConfig is ISocket, AccessControl { // @notice mapping of switchboard address to its id mapping(address => uint64) public switchboardIds; + // @notice buffer to account for gas used by current contract execution + uint256 public gasLimitBuffer; + // @notice error triggered when a switchboard already exists error SwitchboardExists(); + // @notice error triggered when a plug is not connected + error PlugNotConnected(); // @notice event triggered when a new switchboard is added event SwitchboardAdded(address switchboard, uint64 switchboardId); @@ -48,6 +53,7 @@ abstract contract SocketConfig is ISocket, AccessControl { event SwitchboardDisabled(uint64 switchboardId); // @notice event triggered when a switchboard is enabled event SwitchboardEnabled(uint64 switchboardId); + // @notice event triggered when a socket fee manager is updated event SocketFeeManagerUpdated(address oldSocketFeeManager, address newSocketFeeManager); // @notice function to register a switchboard @@ -99,6 +105,25 @@ abstract contract SocketConfig is ISocket, AccessControl { emit PlugConnected(msg.sender, appGatewayId_, switchboardId_); } + /** + * @notice disconnects Plug from Socket + */ + function disconnect() external override { + PlugConfigEvm storage _plugConfig = _plugConfigs[msg.sender]; + if (_plugConfig.appGatewayId == bytes32(0)) revert PlugNotConnected(); + + _plugConfig.appGatewayId = bytes32(0); + _plugConfig.switchboardId = 0; + emit PlugDisconnected(msg.sender); + } + + // @notice function to set the gas limit buffer for socket + // @dev only callable by governance role + // @param gasLimitBuffer_ gas limit buffer for socket + function setGasLimitBuffer(uint256 gasLimitBuffer_) external onlyRole(GOVERNANCE_ROLE) { + gasLimitBuffer = gasLimitBuffer_; + } + // @notice function to set the max copy bytes for socket // @dev only callable by governance role // @param maxCopyBytes_ max copy bytes for socket diff --git a/contracts/protocol/base/PlugBase.sol b/contracts/protocol/base/PlugBase.sol index 856ff24d..46c9bf9b 100644 --- a/contracts/protocol/base/PlugBase.sol +++ b/contracts/protocol/base/PlugBase.sol @@ -46,8 +46,7 @@ abstract contract PlugBase is IPlug { /// @notice Disconnects the plug from the socket function _disconnectSocket() internal { - (, uint64 switchboardId) = socket__.getPlugConfig(address(this)); - socket__.connect(bytes32(0), switchboardId); + socket__.disconnect(); emit ConnectorPlugDisconnected(); } diff --git a/contracts/protocol/interfaces/ISocket.sol b/contracts/protocol/interfaces/ISocket.sol index 7083c36a..04bc8d85 100644 --- a/contracts/protocol/interfaces/ISocket.sol +++ b/contracts/protocol/interfaces/ISocket.sol @@ -32,6 +32,12 @@ interface ISocket { */ event PlugConnected(address plug, bytes32 appGatewayId, uint64 switchboardId); + /** + * @notice emits the config set by a plug for a remoteChainSlug + * @param plug address of plug on current chain + */ + event PlugDisconnected(address plug); + /** * @notice emits the payload details when a new payload arrives at outbound * @param triggerId trigger id @@ -64,6 +70,11 @@ interface ISocket { */ function connect(bytes32 appGatewayId_, uint64 switchboardId_) external; + /** + * @notice disconnects Plug from Socket + */ + function disconnect() external; + /** * @notice registers a switchboard for the socket */ diff --git a/test/FeesTest.t.sol b/test/FeesTest.t.sol index 401f645b..7fdf9d3e 100644 --- a/test/FeesTest.t.sol +++ b/test/FeesTest.t.sol @@ -90,11 +90,9 @@ contract FeesTest is AppGatewayBaseSetup { } function testDisconnectFeesPlug() public { - uint64 sbId = arbConfig.switchboard.switchboardId(); - // disconnect old fees plug hoax(socketOwner); - arbConfig.feesPlug.connectSocket(bytes32(0), address(arbConfig.socket), sbId); + arbConfig.feesPlug.disconnectSocket(); hoax(watcherEOA); feesManager.setFeesPlug(arbChainSlug, bytes32(0)); @@ -133,7 +131,7 @@ contract FeesTest is AppGatewayBaseSetup { // disconnect old fees plug hoax(socketOwner); - oldFeesPlug.connectSocket(bytes32(0), address(arbConfig.socket), sbId); + oldFeesPlug.disconnectSocket(); // deploy new fees plug arbConfig.feesPlug = new FeesPlug(address(arbConfig.socket), address(socketOwner)); diff --git a/test/mock/MockSocket.sol b/test/mock/MockSocket.sol index 4910b242..a88f9b76 100644 --- a/test/mock/MockSocket.sol +++ b/test/mock/MockSocket.sol @@ -36,6 +36,8 @@ contract MockSocket is ISocket { function connect(bytes32 appGatewayId_, uint64 switchboardId_) external override {} + function disconnect() external override {} + function registerSwitchboard() external override returns (uint64 switchboardId) {} ////////////////////////////////////////////////////////