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
18 changes: 10 additions & 8 deletions EventTopics.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
| `AppGatewayCallRequested` | `(triggerId: bytes32, appGatewayId: bytes32, switchboardId: uint64, plug: bytes32, overrides: bytes, payload: bytes)` | `0x8ff0599581fd62c5733e52cea3abd7874731f4a9f86ebb929e5e4afe103f74d4` |
| `ExecutionFailed` | `(payloadId: bytes32, exceededMaxCopy: bool, returnData: bytes)` | `0x385334bc68a32c4d164625189adc7633e6074eb1b837fb4d11d768245151e4ce` |
| `ExecutionSuccess` | `(payloadId: bytes32, exceededMaxCopy: bool, returnData: bytes)` | `0x324d63a433b21a12b90e79cd2ba736b2a5238be6165e03b750fa4a7d5193d5d9` |
| `GasLimitBufferUpdated` | `(gasLimitBuffer: uint256)` | `0xd0e3eb5d0d212f0a08af2be98373721fc901ed26fbac645e08bd664fef818366` |
| `MaxCopyBytesUpdated` | `(maxCopyBytes: uint16)` | `0x294d0c11af52572317e5a0e1362cbf85b3b7c1f7b3f6c7b7e3e5c29c76da33e2` |
| `OwnershipHandoverCanceled` | `(pendingOwner: address)` | `0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92` |
| `OwnershipHandoverRequested` | `(pendingOwner: address)` | `0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d` |
| `OwnershipTransferred` | `(oldOwner: address, newOwner: address)` | `0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0` |
Expand Down Expand Up @@ -287,14 +289,14 @@

## SchedulePrecompile

| Event | Arguments | Topic |
| ------------------------------ | ---------------------------------------------------------------- | -------------------------------------------------------------------- |
| `ExpiryTimeSet` | `(expiryTime_: uint256)` | `0x07e837e13ad9a34715a6bd45f49bbf12de19f06df79cb0be12b3a7d7f2397fa9` |
| `MaxScheduleDelayInSecondsSet` | `(maxScheduleDelayInSeconds_: uint256)` | `0xfd5e4f0e96753ffb08a583390c2f151c51001d8e560625ab93b7fa7b4dac6d75` |
| `ScheduleCallbackFeesSet` | `(scheduleCallbackFees_: uint256)` | `0x82a2f41efc81ce7bfabc0affda7354dae42a3d09bd74a6196e8904b223138a52` |
| `ScheduleFeesPerSecondSet` | `(scheduleFeesPerSecond_: uint256)` | `0x7901a21229f6d2543d8676f53e21214d15f42513e7d46e0dcb510357222bdc7c` |
| `ScheduleRequested` | `(payloadId: bytes32, executeAfter: uint256, deadline: uint256)` | `0xd099d3e3d0f0e2c9c40e0066affeea125aab71d763b7ab0a279ccec3dff70b64` |
| `ScheduleResolved` | `(payloadId: bytes32)` | `0x925dc6c3ebffa07cac89d6e9675f1a5d04e045f2ed9a4fa442665935cb73e26b` |
| Event | Arguments | Topic |
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| `ExpiryTimeSet` | `(expiryTime_: uint256)` | `0x07e837e13ad9a34715a6bd45f49bbf12de19f06df79cb0be12b3a7d7f2397fa9` |
| `MaxScheduleDelayInSecondsSet` | `(maxScheduleDelayInSeconds_: uint256)` | `0xfd5e4f0e96753ffb08a583390c2f151c51001d8e560625ab93b7fa7b4dac6d75` |
| `ScheduleCallbackFeesSet` | `(scheduleCallbackFees_: uint256)` | `0x82a2f41efc81ce7bfabc0affda7354dae42a3d09bd74a6196e8904b223138a52` |
| `ScheduleFeesPerSecondSet` | `(scheduleFeesPerSecond_: uint256)` | `0x7901a21229f6d2543d8676f53e21214d15f42513e7d46e0dcb510357222bdc7c` |
| `ScheduleRequested` | `(payloadId: bytes32, executeAfter: uint256, deadline: uint256, localInvoker: address, callbackSelector: bytes4, callbackData: bytes)` | `0xbeceaccdb128631e58b881241d4fb46e53d8b2b2aa3f1ce77ba6fb80af038e30` |
| `ScheduleResolved` | `(payloadId: bytes32)` | `0x925dc6c3ebffa07cac89d6e9675f1a5d04e045f2ed9a4fa442665935cb73e26b` |

## WritePrecompile

Expand Down
4 changes: 2 additions & 2 deletions FunctionSignatures.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
| `consumeFrom` | `0x40dd78be` |
| `creationCodeWithArgs` | `0xc126dcc4` |
| `deployForwarder__` | `0xd4e3b034` |
| `endAuction` | `0x1212e653` |
| `endAuction` | `0x7426f0f6` |
| `evmxSlug` | `0x8bae77c2` |
| `expireBid` | `0x1dd5022c` |
| `expireBid` | `0x33b5b234` |
| `feesManager__` | `0x70568b58` |
| `forwarderAddresses` | `0x5390fdcb` |
| `getOnChainAddress` | `0xb6abffd7` |
Expand Down
25 changes: 14 additions & 11 deletions contracts/evmx/AuctionManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,10 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AppGatewayBase,
}

/// @notice Ends an auction
/// @param requestCount_ The ID of the auction
function endAuction(uint40 requestCount_) external override onlyPromises {
/// @param data The encoded request count
function endAuction(bytes memory data, bytes memory) external onlyPromises {
uint40 requestCount_ = abi.decode(data, (uint40));
if (requestCount_ == 0) revert InvalidBid();
if (
auctionStatus[requestCount_] == AuctionStatus.CLOSED ||
auctionStatus[requestCount_] == AuctionStatus.NOT_STARTED
Expand Down Expand Up @@ -207,26 +209,27 @@ contract AuctionManager is AuctionManagerStorage, Initializable, AppGatewayBase,
/// @notice Expires a bid and restarts an auction in case a request is not fully executed.
/// @dev Auction can be restarted only for `maxReAuctionCount` times.
/// @dev It also unblocks the fees from last transmitter to be assigned to the new winner.
/// @param requestCount_ The request id
function expireBid(uint40 requestCount_) external override onlyPromises {
if (reAuctionCount[requestCount_] >= maxReAuctionCount) revert MaxReAuctionCountReached();
RequestParams memory requestParams = watcher__().getRequestParams(requestCount_);
/// @param data The encoded request count
function expireBid(bytes memory data, bytes memory) external override onlyPromises {
uint40 requestCount = abi.decode(data, (uint40));
if (reAuctionCount[requestCount] >= maxReAuctionCount) revert MaxReAuctionCountReached();
RequestParams memory requestParams = watcher__().getRequestParams(requestCount);

// if executed or cancelled, bid is not expired
if (
requestParams.requestTrackingParams.payloadsRemaining == 0 ||
requestParams.requestTrackingParams.isRequestCancelled
) return;

delete winningBids[requestCount_];
auctionStatus[requestCount_] = AuctionStatus.RESTARTED;
reAuctionCount[requestCount_]++;
delete winningBids[requestCount];
auctionStatus[requestCount] = AuctionStatus.RESTARTED;
reAuctionCount[requestCount]++;

watcher__().requestHandler__().assignTransmitter(
requestCount_,
requestCount,
Bid({fee: 0, transmitter: address(0), extraData: ""})
);
emit AuctionRestarted(requestCount_);
emit AuctionRestarted(requestCount);
}

function _createRequest(
Expand Down
9 changes: 5 additions & 4 deletions contracts/evmx/interfaces/IAuctionManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,15 @@ interface IAuctionManager {
) external;

/// @notice Ends an auction
/// @param requestCount_ The request count
function endAuction(uint40 requestCount_) external;
/// @param data The encoded request count
function endAuction(bytes memory data, bytes memory) external;

/// @notice Expires a bid and restarts an auction in case a request is not fully executed.
/// @dev Auction can be restarted only for `maxReAuctionCount` times.
/// @dev It also unblocks the fees from last transmitter to be assigned to the new winner.
/// @param requestCount_ The request id
function expireBid(uint40 requestCount_) external;
/// @param data The encoded request count
/// @param returnData The return data from the bid
function expireBid(bytes memory data, bytes memory returnData) external;

/// @notice Checks if an auction is closed
/// @param requestCount_ The request count
Expand Down
6 changes: 6 additions & 0 deletions contracts/evmx/interfaces/IPromise.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ interface IPromise {
/// @dev The callback will be executed on this address
function localInvoker() external view returns (address);

/// @notice The callback selector of the promise
function callbackSelector() external view returns (bytes4);

/// @notice The callback data of the promise
function callbackData() external view returns (bytes memory);

/// @notice The request count of the promise
function requestCount() external view returns (uint40);

Expand Down
22 changes: 20 additions & 2 deletions contracts/evmx/watcher/precompiles/SchedulePrecompile.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
pragma solidity ^0.8.21;

import "../../interfaces/IPrecompile.sol";
import "../../interfaces/IPromise.sol";

import "../../../utils/common/Structs.sol";
import {InvalidScheduleDelay, ResolvingScheduleTooEarly} from "../../../utils/common/Errors.sol";
import "../../../utils/RescueFundsLib.sol";
Expand Down Expand Up @@ -32,7 +34,14 @@ contract SchedulePrecompile is IPrecompile, WatcherBase {
/// @notice Emitted when the expiry time for a schedule is set
event ExpiryTimeSet(uint256 expiryTime_);
/// @notice Emitted when a schedule is requested
event ScheduleRequested(bytes32 payloadId, uint256 executeAfter, uint256 deadline);
event ScheduleRequested(
bytes32 payloadId,
uint256 executeAfter,
uint256 deadline,
address localInvoker,
bytes4 callbackSelector,
bytes callbackData
);
/// @notice Emitted when a schedule is resolved
event ScheduleResolved(bytes32 payloadId);

Expand Down Expand Up @@ -128,8 +137,17 @@ contract SchedulePrecompile is IPrecompile, WatcherBase {
precompileData = abi.encode(delayInSeconds, executeAfter);
fees = getPrecompileFees(precompileData);

IPromise promise_ = IPromise(payloadParams.asyncPromise);

// emits event for watcher to track schedule and resolve when deadline is reached
emit ScheduleRequested(payloadParams.payloadId, executeAfter, deadline);
emit ScheduleRequested(
payloadParams.payloadId,
executeAfter,
deadline,
promise_.localInvoker(),
promise_.callbackSelector(),
promise_.callbackData()
);
}

function resolvePayload(PayloadParams calldata payloadParams_) external onlyRequestHandler {
Expand Down
80 changes: 52 additions & 28 deletions contracts/protocol/Socket.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,22 @@ import {createPayloadId} from "../utils/common/IdUtils.sol";
contract Socket is SocketUtils {
using LibCall for address;

// @notice mapping of payload id to execution status
// mapping of payload id to execution status
mapping(bytes32 => ExecutionStatus) public payloadExecuted;

// @notice mapping of payload id to execution status
// mapping of payload id to digest
mapping(bytes32 => bytes32) public payloadIdToDigest;

////////////////////////////////////////////////////////
////////////////////// ERRORS //////////////////////////
////////////////////////////////////////////////////////
/**
* @dev Error emitted when a payload has already been executed
*/
/// @notice Thrown when a payload has already been executed
error PayloadAlreadyExecuted(ExecutionStatus status);
/**
* @dev Error emitted when verification fails
*/
/// @notice Thrown when verification fails
error VerificationFailed();
/**
* @dev Error emitted when less gas limit is provided for execution than expected
*/
/// @notice Thrown when less gas limit is provided for execution than expected
error LowGasLimit();
/**
* @dev Error emitted when the message value is insufficient
*/
/// @notice Thrown when the message value is insufficient
error InsufficientMsgValue();

/**
Expand All @@ -56,6 +48,10 @@ contract Socket is SocketUtils {

/**
* @notice Executes a payload that has been delivered by transmitters and authenticated by switchboards
* @param executeParams_ The execution parameters
* @param transmissionParams_ The transmission parameters
* @return success True if the payload was executed successfully
* @return returnData The return data from the execution
*/
function execute(
ExecuteParams calldata executeParams_,
Expand All @@ -67,10 +63,11 @@ contract Socket is SocketUtils {
// check if the call type is valid
if (executeParams_.callType != WRITE) revert InvalidCallType();

PlugConfigEvm memory plugConfig = _plugConfigs[executeParams_.target];
// check if the plug is disconnected
// check if the plug is connected
PlugConfigEvm storage plugConfig = _plugConfigs[executeParams_.target];
if (plugConfig.appGatewayId == bytes32(0)) revert PlugNotFound();

// check if the message value is sufficient
if (msg.value < executeParams_.value + transmissionParams_.socketFees)
revert InsufficientMsgValue();

Expand All @@ -85,12 +82,21 @@ contract Socket is SocketUtils {

// verify the digest
_verify(payloadId, plugConfig, executeParams_, transmissionParams_.transmitterProof);

// execute the payload
return _execute(payloadId, executeParams_, transmissionParams_);
}

////////////////////////////////////////////////////////
////////////////// INTERNAL FUNCS //////////////////////
////////////////////////////////////////////////////////
/**
* @notice Verifies the digest of the payload
* @param payloadId_ The id of the payload
* @param plugConfig_ The plug configuration
* @param executeParams_ The execution parameters (appGatewayId, value, payloadPointer, callType, gasLimit)
* @param transmitterProof_ The transmitter proof
*/
function _verify(
bytes32 payloadId_,
PlugConfigEvm memory plugConfig_,
Expand Down Expand Up @@ -123,9 +129,10 @@ contract Socket is SocketUtils {
}

/**
* This function assumes localPlug_ will have code while executing. As the payload
* execution failure is not blocking the system, it is not necessary to check if
* code exists in the given address.
* @notice Executes the payload
* @param payloadId_ The id of the payload
* @param executeParams_ The execution parameters (appGatewayId, value, payloadPointer, callType, gasLimit)
* @param transmissionParams_ The transmission parameters (socketFees, transmitterProof, refundAddress)
*/
function _execute(
bytes32 payloadId_,
Expand All @@ -148,6 +155,7 @@ contract Socket is SocketUtils {
if (success) {
emit ExecutionSuccess(payloadId_, exceededMaxCopy, returnData);

// pay and check fees
if (address(socketFeeManager) != address(0)) {
socketFeeManager.payAndCheckFees{value: transmissionParams_.socketFees}(
executeParams_,
Expand All @@ -157,17 +165,20 @@ contract Socket is SocketUtils {
} else {
payloadExecuted[payloadId_] = ExecutionStatus.Reverted;

address receiver = transmissionParams_.refundAddress == address(0)
? msg.sender
: transmissionParams_.refundAddress;
// refund the fees
address receiver = transmissionParams_.refundAddress;
if (receiver == address(0)) receiver = msg.sender;
SafeTransferLib.forceSafeTransferETH(receiver, msg.value);
emit ExecutionFailed(payloadId_, exceededMaxCopy, returnData);
}
return (success, returnData);
}

/// @notice Validates the execution status of a payload
/// @dev This function can be retried till execution status is executed
/**
* @notice Validates the execution status of a payload
* @dev This function can be retried till execution status is executed
* @param payloadId_ The id of the payload
*/
function _validateExecutionStatus(bytes32 payloadId_) internal {
if (payloadExecuted[payloadId_] == ExecutionStatus.Executed)
revert PayloadAlreadyExecuted(payloadExecuted[payloadId_]);
Expand All @@ -179,13 +190,21 @@ contract Socket is SocketUtils {
////////////////////// Trigger //////////////////////
////////////////////////////////////////////////////////

/// @notice To trigger to a connected remote chain. Should only be called by a plug.
/**
* @notice To trigger to a connected remote chain. Should only be called by a plug.
* @param data_ The data to trigger the app gateway
* @return triggerId The id of the trigger
*/
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.
* @param plug_ The address of the plug
* @param value_ The value to trigger the app gateway
* @param data_ The data to trigger the app gateway
* @return triggerId The id of the trigger
*/
function _triggerAppGateway(
address plug_,
Expand Down Expand Up @@ -220,14 +239,19 @@ contract Socket is SocketUtils {
);
}

/// @notice Fallback function that forwards all calls to Socket's callAppGateway
/// @dev The calldata is passed as-is to the gateways
/**
* @notice Fallback function that forwards all calls to Socket's callAppGateway
* @dev The calldata is passed as-is to the gateways
* @return The trigger id
*/
fallback(bytes calldata) external payable returns (bytes memory) {
// return the trigger id
return abi.encode(_triggerAppGateway(msg.sender, msg.value, msg.data));
}

/// @notice Receive function that forwards all calls to Socket's callAppGateway
/**
* @notice Sending ETH to the socket will revert
*/
receive() external payable {
revert("Socket does not accept ETH");
}
Expand Down
Loading