Contract Name:
SwitchboardPlug
Contract Source Code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/*//////////////////////////////////////////////////////////////
BUNGEE ERRORS
//////////////////////////////////////////////////////////////*/
error MofaSignatureInvalid();
error InsufficientNativeAmount();
error UnsupportedRequest();
error RouterNotRegistered();
error CallerNotBungeeGateway();
error CallerNotEntrypoint();
error SwapOutputInsufficient();
error MinOutputNotMet();
error InvalidRequest();
error FulfilmentDeadlineNotMet();
error CallerNotDelegate();
error InvalidMsg();
error RequestProcessed();
error RequestNotProcessed();
error InvalidSwitchboard();
error PromisedAmountNotMet();
error MsgReceiveFailed();
error RouterAlreadyRegistered();
error InvalidFulfil();
error NotImplemented();
error OnlyOwner();
error OnlyNominee();
error InvalidReceiver();
error ImplAlreadyRegistered();
error InvalidAddress();
/*//////////////////////////////////////////////////////////////
SWITCHBOARD ERRORS
//////////////////////////////////////////////////////////////*/
error NotSiblingBungeeGateway();
error NotSocket();
error NotSwitchboardRouter();
error NotSwitchboardPlug();
error SwitchboardPlugZero();
error ConnectionAlreadyInitialised();
error IncorrectSwitchboard();
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;
import {ISocket} from "../interfaces/ISocket.sol";
import {ISwitchboardRouter} from "../interfaces/ISwitchboardRouter.sol";
import {ISwitchboardPlug} from "../interfaces/ISwitchboardPlug.sol";
import {IPlug} from "../interfaces/IPlug.sol";
import {NotSocket, NotSwitchboardRouter} from "../common/Errors.sol";
/// @title SwitchboardPlug
/// @notice Plugs are application that can communicate across chains on Socket DL
/// @notice SwitchboardPlug is a plug that can via a specific Switchboard on Socket DL
contract SwitchboardPlug is IPlug, ISwitchboardPlug {
/*//////////////////////////////////////////////////////////////////////////
PUBLIC STORAGE
//////////////////////////////////////////////////////////////////////////*/
/// @notice Socket contract - Settlement layer
ISocket public immutable SOCKET;
/// @notice SwitchboardRouter contract
ISwitchboardRouter public immutable SWITCHBOARD_ROUTER;
/// @notice SwitchboardId assigned to this SwitchboardPlug
uint32 public immutable SWITCHBOARD_ID;
/// @notice address of switchboard which will validate the incoming messages to the current chain
address public immutable INBOUND_SWITCHBOARD;
/// @notice address of switchboard which will process outgoing messages to the siblingChain
address public immutable OUTBOUND_SWITCHBOARD;
/// @notice maps siblingChainSlug to bool to indicate if that chain is already configured
mapping(uint32 siblingChainSlug => bool configured) public isConfigured;
constructor(
address _socket,
address _switchboardRouter,
address _inboundSwitchboard,
address _outboundSwitchboard,
uint32 _switchboardId
) {
SOCKET = ISocket(_socket);
SWITCHBOARD_ROUTER = ISwitchboardRouter(_switchboardRouter);
INBOUND_SWITCHBOARD = _inboundSwitchboard;
OUTBOUND_SWITCHBOARD = _outboundSwitchboard;
SWITCHBOARD_ID = _switchboardId;
}
/*//////////////////////////////////////////////////////////////////////////
EXTERNAL FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/
/// @notice Calls Socket to initialize connection with sibling switchboardPlug to send/receive messages
/// @param siblingChainSlug chainSlug of the sibling chain
/// @param siblingPlug address of the sibling Plug
function connect(uint32 siblingChainSlug, address siblingPlug) external {
// checks if the caller is Switchboard Router
_checkIfSwitchboardRouter();
// stores connection status
isConfigured[siblingChainSlug] = true;
// calls Socket to initialise connection
SOCKET.connect(siblingChainSlug, siblingPlug, INBOUND_SWITCHBOARD, OUTBOUND_SWITCHBOARD);
}
/// @notice Called by SwitchboardRouter to send outgoing settlement messages
/// @param siblingChainSlug chainSlug of the sibling chain the message is to be sent to
/// @param msgGasLimit gasLimit required to execute the message on the sibling chain
/// @param payload payload to be executed on the sibling chain
function outbound(uint32 siblingChainSlug, uint256 msgGasLimit, bytes calldata payload) external payable {
// checks if the caller is Switchboard Router
_checkIfSwitchboardRouter();
// sends message to Socket
/// @dev bytes32(0) indicates fast finality transmission
SOCKET.outbound{value: msg.value}(siblingChainSlug, msgGasLimit, bytes32(0), bytes32(0), payload);
}
/// @notice Called by Socket to receive incoming messages on the destination chain
/// @param siblingChainSlug chainSlug of the chain the message originated from
/// @param payload payload sent from the originating chain
function inbound(uint32 siblingChainSlug, bytes calldata payload) external payable {
// checks if the caller is Socket
_checkIfSocket();
// Calls SwitchboardRouter with the incoming message
SWITCHBOARD_ROUTER.receiveAndDeliverMsg(SWITCHBOARD_ID, siblingChainSlug, payload);
}
/*//////////////////////////////////////////////////////////////////////////
INTERNAL FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/
/// @notice checks if caller is Switchboard Router
function _checkIfSwitchboardRouter() internal view {
if (msg.sender != address(SWITCHBOARD_ROUTER)) revert NotSwitchboardRouter();
}
/// @notice checks if caller is Socket
function _checkIfSocket() internal view {
if (msg.sender != address(SOCKET)) revert NotSocket();
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/**
* @title IPlug
* @notice Interface for a plug contract that executes the message received from a source chain.
*/
interface IPlug {
/**
* @dev this should be only executable by socket
* @notice executes the message received from source chain
* @notice It is expected to have original sender checks in the destination plugs using payload
* @param srcChainSlug_ chain slug of source
* @param payload_ the data which is needed by plug at inbound call on remote
*/
function inbound(uint32 srcChainSlug_, bytes calldata payload_) external payable;
}
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.19;
interface ISocketConfig {
function getPlugConfig(
address plugAddress_,
uint32 siblingChainSlug_
)
external
view
returns (
address siblingPlug,
address inboundSwitchboard__,
address outboundSwitchboard__,
address capacitor__,
address decapacitor__
);
}
/**
* @title ISocket
* @notice An interface for a cross-chain communication contract
* @dev This interface provides methods for transmitting and executing messages between chains,
* connecting a plug to a remote chain and setting up switchboards for the message transmission
* This interface also emits events for important operations such as message transmission, execution status,
* and plug connection
*/
interface ISocket is ISocketConfig {
/**
* @notice registers a message
* @dev Packs the message and includes it in a packet with capacitor
* @param remoteChainSlug_ the remote chain slug
* @param minMsgGasLimit_ the gas limit needed to execute the payload on remote
* @param payload_ the data which is needed by plug at inbound call on remote
*/
function outbound(
uint32 remoteChainSlug_,
uint256 minMsgGasLimit_,
bytes32 executionParams_,
bytes32 transmissionParams_,
bytes calldata payload_
) external payable returns (bytes32 msgId);
/**
* @notice sets the config specific to the plug
* @param siblingChainSlug_ the sibling chain slug
* @param siblingPlug_ address of plug present at sibling chain to call inbound
* @param inboundSwitchboard_ the address of switchboard to use for receiving messages
* @param outboundSwitchboard_ the address of switchboard to use for sending messages
*/
function connect(
uint32 siblingChainSlug_,
address siblingPlug_,
address inboundSwitchboard_,
address outboundSwitchboard_
) external;
event PlugConnected(
address plug,
uint32 siblingChainSlug,
address siblingPlug,
address inboundSwitchboard,
address outboundSwitchboard,
address capacitor,
address decapacitor
);
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;
import {IPlug} from "./IPlug.sol";
interface ISwitchboardPlug is IPlug {
function SWITCHBOARD_ID() external view returns (uint32);
function connect(uint32 siblingChainSlug, address siblingPlug) external;
function outbound(uint32 siblingChainSlug, uint256 msgGasLimit, bytes calldata payload) external payable;
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;
interface ISwitchboardRouter {
function sendOutboundMsg(
uint32 originChainId,
uint32 switchboardId,
uint8 msgId,
uint256 destGasLimit,
bytes calldata payload
) external payable;
function receiveAndDeliverMsg(uint32 switchboardId, uint32 siblingChainId, bytes calldata payload) external;
}