Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions contracts/interfaces/ISocket.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.21;

import {ExecuteParams} from "../protocol/utils/common/Structs.sol";
import {ExecuteParams, TransmissionParams} from "../protocol/utils/common/Structs.sol";

/**
* @title ISocket
Expand Down Expand Up @@ -53,7 +53,7 @@ interface ISocket {
*/
function execute(
ExecuteParams memory executeParams_,
bytes memory transmitterSignature_
TransmissionParams memory transmissionParams_
) external payable returns (bytes memory);

/**
Expand Down
3 changes: 2 additions & 1 deletion contracts/interfaces/ISocketBatcher.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ interface ISocketBatcher {
ExecuteParams calldata executeParams_,
bytes32 digest_,
bytes calldata proof_,
bytes calldata transmitterSignature_
bytes calldata transmitterSignature_,
address refundAddress_
) external payable returns (bytes memory);
}
34 changes: 34 additions & 0 deletions contracts/interfaces/ISocketFeeManager.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.21;

import {ExecuteParams, TransmissionParams} from "../protocol/utils/common/Structs.sol";

interface ISocketFeeManager {
/**
* @notice Pays and validates fees for execution
* @param executeParams_ Execute params
* @param transmissionParams_ Transmission params
*/
function payAndCheckFees(
ExecuteParams memory executeParams_,
TransmissionParams memory transmissionParams_
) external payable;

/**
* @notice Gets minimum fees required for execution
* @return nativeFees Minimum native token fees required
*/
function getMinSocketFees() external view returns (uint256 nativeFees);

/**
* @notice Sets socket fees
* @param socketFees_ New socket fees amount
*/
function setSocketFees(uint256 socketFees_) external;

/**
* @notice Gets current socket fees
* @return Current socket fees amount
*/
function socketFees() external view returns (uint256);
}
34 changes: 24 additions & 10 deletions contracts/protocol/socket/Socket.sol
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,22 @@ contract Socket is SocketUtils {
*/
function execute(
ExecuteParams memory executeParams_,
bytes memory transmitterSignature_
TransmissionParams memory transmissionParams_
) external payable returns (bytes memory) {
if (executeParams_.deadline < block.timestamp) revert DeadlinePassed();
PlugConfig memory plugConfig = _plugConfigs[executeParams_.target];
if (plugConfig.appGatewayId == bytes32(0)) revert PlugDisconnected();

if (msg.value < executeParams_.value) revert InsufficientMsgValue();
if (msg.value < executeParams_.value + transmissionParams_.socketFees)
revert InsufficientMsgValue();
bytes32 payloadId = _createPayloadId(plugConfig.switchboard, executeParams_);
_validateExecutionStatus(payloadId);

address transmitter = transmitterSignature_.length > 0
? _recoverSigner(keccak256(abi.encode(address(this), payloadId)), transmitterSignature_)
address transmitter = transmissionParams_.transmitterSignature.length > 0
? _recoverSigner(
keccak256(abi.encode(address(this), payloadId)),
transmissionParams_.transmitterSignature
)
: address(0);

bytes32 digest = _createDigest(
Expand All @@ -69,7 +73,7 @@ contract Socket is SocketUtils {
executeParams_
);
_verify(digest, payloadId, plugConfig.switchboard);
return _execute(payloadId, executeParams_);
return _execute(payloadId, executeParams_, transmissionParams_);
}

////////////////////////////////////////////////////////
Expand All @@ -90,23 +94,33 @@ contract Socket is SocketUtils {
*/
function _execute(
bytes32 payloadId_,
ExecuteParams memory executeParams_
ExecuteParams memory executeParams_,
TransmissionParams memory transmissionParams_
) internal returns (bytes memory) {
if (gasleft() < executeParams_.gasLimit) revert LowGasLimit();

// NOTE: external un-trusted call
(bool success, , bytes memory returnData) = executeParams_.target.tryCall(
msg.value,
executeParams_.value,
executeParams_.gasLimit,
maxCopyBytes,
executeParams_.payload
);

if (!success) {
if (success) {
emit ExecutionSuccess(payloadId_, returnData);
if (address(socketFeeManager) != address(0)) {
socketFeeManager.payAndCheckFees{value: transmissionParams_.socketFees}(
executeParams_,
transmissionParams_
);
}
} else {
payloadExecuted[payloadId_] = ExecutionStatus.Reverted;
address receiver = transmissionParams_.refundAddress == address(0) ? msg.sender : transmissionParams_.refundAddress;
SafeTransferLib.forceSafeTransferETH(receiver, msg.value);

emit ExecutionFailed(payloadId_, returnData);
} else {
emit ExecutionSuccess(payloadId_, returnData);
}

return returnData;
Expand Down
16 changes: 13 additions & 3 deletions contracts/protocol/socket/SocketBatcher.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import "solady/auth/Ownable.sol";
import "../../interfaces/ISocket.sol";
import "../../interfaces/ISwitchboard.sol";
import "../utils/RescueFundsLib.sol";
import {ExecuteParams} from "../../protocol/utils/common/Structs.sol";
import {ExecuteParams, TransmissionParams} from "../../protocol/utils/common/Structs.sol";
import "../../interfaces/ISocketBatcher.sol";

/**
Expand All @@ -30,10 +30,20 @@ contract SocketBatcher is ISocketBatcher, Ownable {
ExecuteParams calldata executeParams_,
bytes32 digest_,
bytes calldata proof_,
bytes calldata transmitterSignature_
bytes calldata transmitterSignature_,
address refundAddress_
) external payable returns (bytes memory) {
ISwitchboard(executeParams_.switchboard).attest(digest_, proof_);
return socket__.execute{value: msg.value}(executeParams_, transmitterSignature_);
return
socket__.execute{value: msg.value}(
executeParams_,
TransmissionParams({
transmitterSignature: transmitterSignature_,
socketFees: 0,
extraData: "",
refundAddress: refundAddress_
})
);
}

function rescueFunds(address token_, address to_, uint256 amount_) external onlyOwner {
Expand Down
12 changes: 11 additions & 1 deletion contracts/protocol/socket/SocketConfig.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@ import "../../interfaces/ISwitchboard.sol";
import "../utils/AccessControl.sol";
import {GOVERNANCE_ROLE, RESCUE_ROLE} from "../utils/common/AccessRoles.sol";
import {PlugConfig, SwitchboardStatus, ExecutionStatus} from "../utils/common/Structs.sol";

import "../../interfaces/ISocketFeeManager.sol";
/**
* @title SocketConfig
* @notice An abstract contract for configuring socket connections for plugs between different chains,
* manages plug configs and switchboard registrations
* @dev This contract is meant to be inherited by other contracts that require socket configuration functionality
*/
abstract contract SocketConfig is ISocket, AccessControl {
// socket fee manager
ISocketFeeManager public socketFeeManager;

// Error triggered when a switchboard already exists
mapping(address => SwitchboardStatus) public isValidSwitchboard;

Expand All @@ -30,6 +33,7 @@ abstract contract SocketConfig is ISocket, AccessControl {
// Event triggered when a new switchboard is added
event SwitchboardAdded(address switchboard);
event SwitchboardDisabled(address switchboard);
event SocketFeeManagerUpdated(address oldSocketFeeManager, address newSocketFeeManager);

function registerSwitchboard() external {
if (isValidSwitchboard[msg.sender] != SwitchboardStatus.NOT_REGISTERED)
Expand All @@ -44,6 +48,12 @@ abstract contract SocketConfig is ISocket, AccessControl {
emit SwitchboardDisabled(msg.sender);
}


function setSocketFeeManager(address socketFeeManager_) external onlyRole(GOVERNANCE_ROLE) {
emit SocketFeeManagerUpdated(address(socketFeeManager), socketFeeManager_);
socketFeeManager = ISocketFeeManager(socketFeeManager_);
}

/**
* @notice connects Plug to Socket and sets the config for given `siblingChainSlug_`
*/
Expand Down
72 changes: 72 additions & 0 deletions contracts/protocol/socket/SocketFeeManager.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.21;

import "../utils/AccessControl.sol";
import {GOVERNANCE_ROLE, RESCUE_ROLE} from "../utils/common/AccessRoles.sol";
import {ExecuteParams, TransmissionParams} from "../../protocol/utils/common/Structs.sol";
import "../../interfaces/ISocketFeeManager.sol";
import "../utils/RescueFundsLib.sol";

/**
* @title SocketFeeManager
* @notice The SocketFeeManager contract is responsible for managing socket fees
*/
contract SocketFeeManager is ISocketFeeManager, AccessControl {
// Current socket fees in native tokens
uint256 public socketFees;

error InsufficientFees();
error FeeTooLow();

event SocketFeesUpdated(uint256 oldFees, uint256 newFees);

/**
* @notice Initializes the SocketFeeManager contract
* @param owner_ The owner of the contract with GOVERNANCE_ROLE
* @param socketFees_ Initial socket fees amount
*/
constructor(address owner_, uint256 socketFees_) {
emit SocketFeesUpdated(0, socketFees_);
socketFees = socketFees_;
_grantRole(GOVERNANCE_ROLE, owner_);
_grantRole(RESCUE_ROLE, owner_);
}

/**
* @notice Pays and validates fees for execution
*/
function payAndCheckFees(ExecuteParams memory, TransmissionParams memory) external payable {
if (msg.value < socketFees) revert InsufficientFees();
}

/**
* @notice Gets minimum fees required for execution
* @return nativeFees Minimum native token fees required
*/
function getMinSocketFees() external view returns (uint256 nativeFees) {
return socketFees;
}

/**
* @notice Sets socket fees
* @param socketFees_ New socket fees amount
*/
function setSocketFees(uint256 socketFees_) external onlyRole(GOVERNANCE_ROLE) {
emit SocketFeesUpdated(socketFees, socketFees_);
socketFees = socketFees_;
}

/**
* @notice Allows owner to rescue stuck funds
* @param token_ Token address (address(0) for native tokens)
* @param to_ Address to send funds to
* @param amount_ Amount of tokens to rescue
*/
function rescueFunds(
address token_,
address to_,
uint256 amount_
) external onlyRole(RESCUE_ROLE) {
RescueFundsLib._rescueFunds(token_, to_, amount_);
}
}
7 changes: 7 additions & 0 deletions contracts/protocol/utils/common/Structs.sol
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,13 @@ struct ExecuteParams {
address switchboard;
}

struct TransmissionParams {
uint256 socketFees;
address refundAddress;
bytes extraData;
bytes transmitterSignature;
}

struct PayloadIdParams {
uint40 requestCount;
uint40 batchCount;
Expand Down
8 changes: 3 additions & 5 deletions test/Inbox.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ contract TriggerTest is DeliveryHelperTest {

// Simulate a message from another chain through the watcher
uint256 incrementValue = 5;
bytes32 triggerId = _encodeTriggerId(address(gateway), arbChainSlug);
bytes32 triggerId = _encodeTriggerId(address(arbConfig.socket), arbChainSlug);
bytes memory payload = abi.encodeWithSelector(
CounterAppGateway.increase.selector,
incrementValue
Expand Down Expand Up @@ -91,12 +91,10 @@ contract TriggerTest is DeliveryHelperTest {
assertEq(gateway.counterVal(), incrementValue, "Gateway counter should be incremented");
}

function _encodeTriggerId(address appGateway_, uint256 chainSlug_) internal returns (bytes32) {
function _encodeTriggerId(address socket_, uint256 chainSlug_) internal returns (bytes32) {
return
bytes32(
(uint256(chainSlug_) << 224) |
(uint256(uint160(appGateway_)) << 64) |
triggerCounter++
(uint256(chainSlug_) << 224) | (uint256(uint160(socket_)) << 64) | triggerCounter++
);
}
}
Loading