Skip to content

Commit a72f95e

Browse files
Merge pull request #199 from SocketDotTech/payload-reverts
feat: payload revert
2 parents fabdffb + dade540 commit a72f95e

File tree

2 files changed

+38
-7
lines changed

2 files changed

+38
-7
lines changed

contracts/evmx/helpers/AsyncPromise.sol

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,16 @@ abstract contract AsyncPromiseStorage is IPromise {
3838
/// @notice The callback data to be used when the promise is resolved.
3939
bytes public callbackData;
4040

41-
// slots [53-102] reserved for gap
42-
uint256[50] _gap_after;
41+
// slot 53
42+
/// @notice The revert handler selector of the promise
43+
bytes4 public revertHandlerSelector;
44+
45+
// slot 54
46+
/// @notice The revert handler data of the promise
47+
bytes public revertHandlerData;
48+
49+
// slots [55-102] reserved for gap
50+
uint256[48] _gap_after;
4351

4452
// slots 103-154 (51) reserved for addr resolver util
4553
}
@@ -133,7 +141,14 @@ contract AsyncPromise is AsyncPromiseStorage, Initializable, AddressResolverUtil
133141
/// @dev Only callable by the watcher.
134142
/// @dev handleRevert function can be retried till it succeeds
135143
function _handleRevert(bytes32 payloadId_) internal {
136-
try IAppGateway(localInvoker).handleRevert(payloadId_) {} catch {
144+
bytes memory combinedCalldata = abi.encodePacked(
145+
revertHandlerSelector,
146+
abi.encode(revertHandlerData, payloadId_)
147+
);
148+
149+
(bool success, , ) = localInvoker.tryCall(0, gasleft(), 0, combinedCalldata);
150+
151+
if (!success) {
137152
// todo: in this case, promise will stay unresolved
138153
revert PromiseRevertFailed();
139154
}
@@ -143,20 +158,31 @@ contract AsyncPromise is AsyncPromiseStorage, Initializable, AddressResolverUtil
143158
/// @param selector_ The function selector for the callback.
144159
/// @param data_ The data to be passed to the callback.
145160
function then(bytes4 selector_, bytes memory data_) external override {
146-
if (msg.sender != localInvoker) revert NotInvoker();
147161
// if the promise is already set up, revert
148162
if (state != AsyncPromiseState.WAITING_FOR_CALLBACK_SELECTOR) {
149163
revert PromiseAlreadySetUp();
150164
}
151-
if (watcher__().latestAsyncPromise() != address(this)) revert NotLatestPromise();
152-
if (requestCount != watcher__().getCurrentRequestCount()) revert RequestCountMismatch();
153-
165+
_validate();
154166
// if the promise is waiting for the callback selector, set it and update the state
155167
callbackSelector = selector_;
156168
callbackData = data_;
157169
state = AsyncPromiseState.WAITING_FOR_CALLBACK_EXECUTION;
158170
}
159171

172+
function error(bytes4 selector_, bytes memory data_) external override {
173+
_validate();
174+
// if the promise is waiting for the callback selector, set it and update the state
175+
revertHandlerSelector = selector_;
176+
revertHandlerData = data_;
177+
state = AsyncPromiseState.WAITING_FOR_CALLBACK_EXECUTION;
178+
}
179+
180+
function _validate() internal {
181+
if (msg.sender != localInvoker) revert NotInvoker();
182+
if (watcher__().latestAsyncPromise() != address(this)) revert NotLatestPromise();
183+
if (requestCount != watcher__().getCurrentRequestCount()) revert RequestCountMismatch();
184+
}
185+
160186
/**
161187
* @notice Rescues funds from the contract if they are locked by mistake. This contract does not
162188
* theoretically need this function but it is added for safety.

contracts/evmx/interfaces/IPromise.sol

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ interface IPromise {
3232
/// @param data_ The data to be passed to the callback.
3333
function then(bytes4 selector_, bytes memory data_) external;
3434

35+
/// @notice Sets the revert handler selector and data for the promise.
36+
/// @param selector_ The function selector for the revert handler.
37+
/// @param data_ The data to be passed to the revert handler.
38+
function error(bytes4 selector_, bytes memory data_) external;
39+
3540
/// @notice Marks the promise as resolved and executes the callback if set.
3641
/// @dev Only callable by the watcher precompile.
3742
/// @param resolvedPromise_ The data returned from the async payload execution.

0 commit comments

Comments
 (0)