From 7067a19ca075507c427b912c23514cc5f6a5954b Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Thu, 24 Jul 2025 17:51:53 +0530 Subject: [PATCH 1/3] feat: verify transmitter sign in sb --- contracts/protocol/Socket.sol | 48 +++++++++++-------- .../protocol/interfaces/ISwitchboard.sol | 14 ++++++ .../protocol/switchboard/SwitchboardBase.sol | 13 +++++ test/mock/MockFastSwitchboard.sol | 8 ++++ 4 files changed, 62 insertions(+), 21 deletions(-) diff --git a/contracts/protocol/Socket.sol b/contracts/protocol/Socket.sol index 5631256b..4c45b303 100644 --- a/contracts/protocol/Socket.sol +++ b/contracts/protocol/Socket.sol @@ -83,25 +83,9 @@ contract Socket is SocketUtils { // validate the execution status _validateExecutionStatus(payloadId); - address transmitter = transmissionParams_.transmitterSignature.length > 0 - ? _recoverSigner( - keccak256(abi.encode(address(this), payloadId)), - transmissionParams_.transmitterSignature - ) - : address(0); - - // create the digest - // transmitter, payloadId, appGateway, executeParams_ and there contents are validated using digest verification from switchboard - bytes32 digest = _createDigest( - transmitter, - payloadId, - plugConfig.appGatewayId, - executeParams_ - ); - payloadIdToDigest[payloadId] = digest; // verify the digest - _verify(digest, payloadId, plugConfig.switchboardId); + _verify(payloadId, plugConfig, executeParams_, transmissionParams_.transmitterSignature); return _execute(payloadId, executeParams_, transmissionParams_); } @@ -109,13 +93,35 @@ contract Socket is SocketUtils { //////////////////////////////////////////////////////// ////////////////// INTERNAL FUNCS ////////////////////// //////////////////////////////////////////////////////// - function _verify(bytes32 digest_, bytes32 payloadId_, uint64 switchboardId_) internal view { - if (isValidSwitchboard[switchboardId_] != SwitchboardStatus.REGISTERED) + function _verify( + bytes32 payloadId_, + PlugConfigEvm memory plugConfig_, + ExecuteParams calldata executeParams_, + bytes calldata transmitterSignature_ + ) internal { + if (isValidSwitchboard[plugConfig_.switchboardId] != SwitchboardStatus.REGISTERED) revert InvalidSwitchboard(); + address transmitter = ISwitchboard(switchboardAddresses[plugConfig_.switchboardId]) + .getTransmitter(msg.sender, payloadId_, transmitterSignature_); + + // create the digest + // transmitter, payloadId, appGateway, executeParams_ and there contents are validated using digest verification from switchboard + bytes32 digest = _createDigest( + transmitter, + payloadId_, + plugConfig_.appGatewayId, + executeParams_ + ); + payloadIdToDigest[payloadId_] = digest; + // NOTE: is the the first un-trusted call in the system, another one is Plug.call - if (!ISwitchboard(switchboardAddresses[switchboardId_]).allowPayload(digest_, payloadId_)) - revert VerificationFailed(); + if ( + !ISwitchboard(switchboardAddresses[plugConfig_.switchboardId]).allowPayload( + digest, + payloadId_ + ) + ) revert VerificationFailed(); } /** diff --git a/contracts/protocol/interfaces/ISwitchboard.sol b/contracts/protocol/interfaces/ISwitchboard.sol index 3434cd45..e8518d64 100644 --- a/contracts/protocol/interfaces/ISwitchboard.sol +++ b/contracts/protocol/interfaces/ISwitchboard.sol @@ -28,4 +28,18 @@ interface ISwitchboard { bytes calldata payload_, bytes calldata overrides_ ) external payable; + + /** + * @notice Gets the transmitter for a given payload + * @notice Switchboard are required to implement this function to allow for the verification of the transmitters + * @param sender_ The sender of the payload + * @param payloadId_ The payload ID + * @param transmitterSignature_ The transmitter signature + * @return The transmitter address + */ + function getTransmitter( + address sender_, + bytes32 payloadId_, + bytes calldata transmitterSignature_ + ) external view returns (address); } diff --git a/contracts/protocol/switchboard/SwitchboardBase.sol b/contracts/protocol/switchboard/SwitchboardBase.sol index aed60da0..a6ae97cb 100644 --- a/contracts/protocol/switchboard/SwitchboardBase.sol +++ b/contracts/protocol/switchboard/SwitchboardBase.sol @@ -33,6 +33,19 @@ abstract contract SwitchboardBase is ISwitchboard, AccessControl { switchboardId = socket__.registerSwitchboard(); } + function getTransmitter( + address sender_, + bytes32 payloadId_, + bytes calldata transmitterSignature_ + ) external view returns (address transmitter) { + transmitter = transmitterSignature_.length > 0 + ? _recoverSigner( + keccak256(abi.encode(address(socket__), payloadId_)), + transmitterSignature_ + ) + : address(0); + } + /// @notice Recovers the signer from the signature /// @param digest_ The digest of the payload /// @param signature_ The signature of the watcher diff --git a/test/mock/MockFastSwitchboard.sol b/test/mock/MockFastSwitchboard.sol index 2dab11dc..24b31cd3 100644 --- a/test/mock/MockFastSwitchboard.sol +++ b/test/mock/MockFastSwitchboard.sol @@ -40,4 +40,12 @@ contract MockFastSwitchboard is ISwitchboard { bytes calldata payload_, bytes calldata overrides_ ) external payable override {} + + function getTransmitter( + address sender_, + bytes32 payloadId_, + bytes calldata transmitterSignature_ + ) external view returns (address) { + return sender_; + } } From 2075b53a3402d593e5b6ed3fc3fbab957466d7f5 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Fri, 25 Jul 2025 00:54:18 +0530 Subject: [PATCH 2/3] fix: rename transmitter sig to proof --- contracts/protocol/Socket.sol | 6 +++--- contracts/protocol/SocketBatcher.sol | 8 ++++---- contracts/utils/common/Structs.sol | 2 +- test/SetupTest.t.sol | 2 +- test/SocketFeeManager.t.sol | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/contracts/protocol/Socket.sol b/contracts/protocol/Socket.sol index 4c45b303..fb4ec6d5 100644 --- a/contracts/protocol/Socket.sol +++ b/contracts/protocol/Socket.sol @@ -85,7 +85,7 @@ contract Socket is SocketUtils { _validateExecutionStatus(payloadId); // verify the digest - _verify(payloadId, plugConfig, executeParams_, transmissionParams_.transmitterSignature); + _verify(payloadId, plugConfig, executeParams_, transmissionParams_.transmitterProof); return _execute(payloadId, executeParams_, transmissionParams_); } @@ -97,13 +97,13 @@ contract Socket is SocketUtils { bytes32 payloadId_, PlugConfigEvm memory plugConfig_, ExecuteParams calldata executeParams_, - bytes calldata transmitterSignature_ + bytes calldata transmitterProof_ ) internal { if (isValidSwitchboard[plugConfig_.switchboardId] != SwitchboardStatus.REGISTERED) revert InvalidSwitchboard(); address transmitter = ISwitchboard(switchboardAddresses[plugConfig_.switchboardId]) - .getTransmitter(msg.sender, payloadId_, transmitterSignature_); + .getTransmitter(msg.sender, payloadId_, transmitterProof_); // create the digest // transmitter, payloadId, appGateway, executeParams_ and there contents are validated using digest verification from switchboard diff --git a/contracts/protocol/SocketBatcher.sol b/contracts/protocol/SocketBatcher.sol index ecaecee8..1f5237cb 100644 --- a/contracts/protocol/SocketBatcher.sol +++ b/contracts/protocol/SocketBatcher.sol @@ -37,7 +37,7 @@ contract SocketBatcher is ISocketBatcher, Ownable { * @param executeParams_ The execution parameters * @param digest_ The digest of the payload * @param proof_ The proof of the payload - * @param transmitterSignature_ The signature of the transmitter + * @param transmitterProof_ The signature of the transmitter * @return The return data after execution */ function attestAndExecute( @@ -45,7 +45,7 @@ contract SocketBatcher is ISocketBatcher, Ownable { address switchboard_, bytes32 digest_, bytes calldata proof_, - bytes calldata transmitterSignature_, + bytes calldata transmitterProof_, address refundAddress_ ) external payable returns (bool, bytes memory) { IFastSwitchboard(switchboard_).attest(digest_, proof_); @@ -53,7 +53,7 @@ contract SocketBatcher is ISocketBatcher, Ownable { socket__.execute{value: msg.value}( executeParams_, TransmissionParams({ - transmitterSignature: transmitterSignature_, + transmitterProof: transmitterProof_, socketFees: 0, extraData: executeParams_.extraData, refundAddress: refundAddress_ @@ -80,7 +80,7 @@ contract SocketBatcher is ISocketBatcher, Ownable { (bool success, bytes memory returnData) = socket__.execute{value: msg.value}( execParams_.executeParams, TransmissionParams({ - transmitterSignature: execParams_.transmitterSignature, + transmitterProof: execParams_.transmitterSignature, socketFees: 0, extraData: execParams_.executeParams.extraData, refundAddress: execParams_.refundAddress diff --git a/contracts/utils/common/Structs.sol b/contracts/utils/common/Structs.sol index 133324e5..aecf197b 100644 --- a/contracts/utils/common/Structs.sol +++ b/contracts/utils/common/Structs.sol @@ -99,7 +99,7 @@ struct TransmissionParams { uint256 socketFees; address refundAddress; bytes extraData; - bytes transmitterSignature; + bytes transmitterProof; } struct WatcherMultiCallParams { diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index 7ba86c54..505d0f62 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -1449,7 +1449,7 @@ contract MessageSwitchboardSetup is DeploySetup { socketFees: 0, refundAddress: socketOwner, extraData: bytes(""), - transmitterSignature: bytes("") + transmitterProof: bytes("") }); optConfig.socket.execute(executeParams, transmissionParams); diff --git a/test/SocketFeeManager.t.sol b/test/SocketFeeManager.t.sol index eb6e6899..e696b95e 100644 --- a/test/SocketFeeManager.t.sol +++ b/test/SocketFeeManager.t.sol @@ -144,7 +144,7 @@ contract SocketFeeManagerTest is AppGatewayBaseSetup { }); TransmissionParams memory transmissionParams = TransmissionParams({ - transmitterSignature: bytes(""), + transmitterProof: bytes(""), socketFees: socketFees, extraData: bytes(""), refundAddress: transmitterEOA From d087e961b442661e786ff3fbe406a91b7d59c3cc Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Fri, 25 Jul 2025 00:54:34 +0530 Subject: [PATCH 3/3] fix: transmitter addr to bytes32 in digest --- contracts/evmx/watcher/precompiles/WritePrecompile.sol | 2 +- contracts/protocol/SocketUtils.sol | 2 +- contracts/protocol/switchboard/MessageSwitchboard.sol | 2 +- contracts/utils/common/Structs.sol | 2 +- test/SetupTest.t.sol | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/contracts/evmx/watcher/precompiles/WritePrecompile.sol b/contracts/evmx/watcher/precompiles/WritePrecompile.sol index 9294f780..7e7c5919 100644 --- a/contracts/evmx/watcher/precompiles/WritePrecompile.sol +++ b/contracts/evmx/watcher/precompiles/WritePrecompile.sol @@ -177,7 +177,7 @@ contract WritePrecompile is WritePrecompileStorage, Initializable, Ownable, Watc // create digest DigestParams memory digestParams_ = DigestParams( configurations__().sockets(transaction.chainSlug), - transmitter_, + toBytes32Format(transmitter_), payloadParams.payloadId, deadline, payloadParams.callType, diff --git a/contracts/protocol/SocketUtils.sol b/contracts/protocol/SocketUtils.sol index 46597144..3e23ede4 100644 --- a/contracts/protocol/SocketUtils.sol +++ b/contracts/protocol/SocketUtils.sol @@ -76,7 +76,7 @@ abstract contract SocketUtils is SocketConfig { keccak256( abi.encodePacked( toBytes32Format(address(this)), - transmitter_, + toBytes32Format(transmitter_), payloadId_, executeParams_.deadline, executeParams_.callType, diff --git a/contracts/protocol/switchboard/MessageSwitchboard.sol b/contracts/protocol/switchboard/MessageSwitchboard.sol index 0fe72dfd..549634eb 100644 --- a/contracts/protocol/switchboard/MessageSwitchboard.sol +++ b/contracts/protocol/switchboard/MessageSwitchboard.sol @@ -166,7 +166,7 @@ contract MessageSwitchboard is SwitchboardBase { digestParams = DigestParams({ socket: siblingSockets[dstChainSlug_], - transmitter: address(0), + transmitter: bytes32(0), payloadId: payloadId, deadline: block.timestamp + 3600, callType: WRITE, diff --git a/contracts/utils/common/Structs.sol b/contracts/utils/common/Structs.sol index aecf197b..4503068d 100644 --- a/contracts/utils/common/Structs.sol +++ b/contracts/utils/common/Structs.sol @@ -130,7 +130,7 @@ struct UserCredits { // digest: struct DigestParams { bytes32 socket; - address transmitter; + bytes32 transmitter; bytes32 payloadId; uint256 deadline; bytes4 callType; diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index 505d0f62..ae6dac61 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -919,7 +919,7 @@ contract WatcherSetup is AuctionSetup { ); digestParams = DigestParams( toBytes32Format(address(getSocketConfig(transaction.chainSlug).socket)), - transmitterEOA, + toBytes32Format(transmitterEOA), payloadParams.payloadId, payloadParams.deadline, payloadParams.callType, @@ -1396,7 +1396,7 @@ contract MessageSwitchboardSetup is DeploySetup { bytes memory extraData = abi.encode(srcChainSlug_, toBytes32Format(srcPlug_)); digestParams = DigestParams({ socket: toBytes32Format(dstSocket_), - transmitter: address(0), + transmitter: bytes32(0), payloadId: payloadId_, deadline: block.timestamp + 3600, callType: WRITE,