@@ -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.
0 commit comments