From aef1ebb806400b36d990d471535db02160e1aa3d Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Thu, 17 Apr 2025 18:03:40 +0530 Subject: [PATCH 1/3] feat: watcher precompile fees and callback fees --- .../protocol/payload-delivery/FeesManager.sol | 28 ++++++++++++----- .../app-gateway/DeliveryHelper.sol | 3 +- .../app-gateway/RequestQueue.sol | 2 +- .../watcherPrecompile/core/RequestHandler.sol | 11 ++++--- .../core/WatcherPrecompile.sol | 31 +++++++++---------- .../core/WatcherPrecompileCore.sol | 25 +++++++++++++++ .../core/WatcherPrecompileStorage.sol | 8 +++-- 7 files changed, 75 insertions(+), 33 deletions(-) diff --git a/contracts/protocol/payload-delivery/FeesManager.sol b/contracts/protocol/payload-delivery/FeesManager.sol index f3eaf0f3..53ac31bb 100644 --- a/contracts/protocol/payload-delivery/FeesManager.sol +++ b/contracts/protocol/payload-delivery/FeesManager.sol @@ -51,6 +51,8 @@ abstract contract FeesManagerStorage is IFeesManager { /// @dev signatureNonce => isNonceUsed mapping(uint256 => bool) public isNonceUsed; + mapping(uint40 => address) public requestCountConsumeFrom; + // slots [57-106] reserved for gap uint256[50] _gap_after; @@ -299,15 +301,14 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol uint32 chainSlug_, address token_, uint256 amount_, - address consumeFrom_ + uint40 requestCount_ ) external onlyWatcherPrecompile { - address appGateway = _getCoreAppGateway(consumeFrom_); - TokenBalance storage tokenBalance = userFeeBalances[appGateway][chainSlug_][token_]; - if (tokenBalance.deposited < amount_) - revert InsufficientWatcherPrecompileFeesAvailable(chainSlug_, token_, consumeFrom_); - tokenBalance.deposited -= amount_; + Fees storage fees = requestCountBlockedFees[requestCount_]; + if (fees.amount == 0) revert NoFeesBlocked(); + + fees.amount -= amount_; watcherPrecompileFees[chainSlug_][token_] += amount_; - emit WatcherPrecompileFeesAssigned(chainSlug_, token_, amount_, consumeFrom_); + emit WatcherPrecompileFeesAssigned(chainSlug_, token_, amount_, requestCount_); } function unblockFees(uint40 requestCount_) external { @@ -412,7 +413,18 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol readAt: 0, payload: payload_ }); - requestCount = watcherPrecompile__().submitRequest(payloadSubmitParamsArray); + + RequestMetadata memory requestMetadata = RequestMetadata({ + appGateway: address(this), + auctionManager: address(0), + feesApprovalData: bytes(""), + fees: Fees({token: token_, amount: amount_}), + winningBid: Bid({transmitter: transmitter_, fee: 0, extraData: new bytes(0)}) + }); + requestCount = watcherPrecompile__().submitRequest( + payloadSubmitParamsArray, + requestMetadata + ); // same transmitter can execute requests without auction watcherPrecompile__().startProcessingRequest(requestCount, transmitter_); diff --git a/contracts/protocol/payload-delivery/app-gateway/DeliveryHelper.sol b/contracts/protocol/payload-delivery/app-gateway/DeliveryHelper.sol index 6df859ac..6c7b0c80 100644 --- a/contracts/protocol/payload-delivery/app-gateway/DeliveryHelper.sol +++ b/contracts/protocol/payload-delivery/app-gateway/DeliveryHelper.sol @@ -41,7 +41,7 @@ contract DeliveryHelper is FeesHelpers { requestMetadata_.winningBid.transmitter = winningBid_.transmitter; if (!isRestarted) { - watcherPrecompile__().startProcessingRequest(requestCount_, winningBid_.transmitter); + watcherPrecompile__().startProcessingRequest(requestCount_, winningBid_); } else { watcherPrecompile__().updateTransmitter(requestCount_, winningBid_.transmitter); } @@ -52,6 +52,7 @@ contract DeliveryHelper is FeesHelpers { function finishRequest(uint40 requestCount_) external onlyWatcherPrecompile { RequestMetadata storage requestMetadata_ = requests[requestCount_]; + // todo: move it to watcher precompile if (requestMetadata_.winningBid.transmitter != address(0)) IFeesManager(addressResolver__.feesManager()).unblockAndAssignFees( requestCount_, diff --git a/contracts/protocol/payload-delivery/app-gateway/RequestQueue.sol b/contracts/protocol/payload-delivery/app-gateway/RequestQueue.sol index a3d7e801..be9cabf7 100644 --- a/contracts/protocol/payload-delivery/app-gateway/RequestQueue.sol +++ b/contracts/protocol/payload-delivery/app-gateway/RequestQueue.sol @@ -89,7 +89,7 @@ abstract contract RequestQueue is DeliveryUtils { }); // process and submit the queue of payloads to watcher precompile - requestCount = watcherPrecompile__().submitRequest(payloadSubmitParamsArray); + requestCount = watcherPrecompile__().submitRequest(payloadSubmitParamsArray, requestMetadata); requests[requestCount] = requestMetadata; // send query directly if request contains only reads diff --git a/contracts/protocol/watcherPrecompile/core/RequestHandler.sol b/contracts/protocol/watcherPrecompile/core/RequestHandler.sol index 0d3a2851..3d00e32d 100644 --- a/contracts/protocol/watcherPrecompile/core/RequestHandler.sol +++ b/contracts/protocol/watcherPrecompile/core/RequestHandler.sol @@ -19,7 +19,8 @@ abstract contract RequestHandler is WatcherPrecompileCore { /// @dev This function processes a batch of payload requests and assigns them to batches /// @dev It also consumes limits for the app gateway based on the number of reads and writes function submitRequest( - PayloadSubmitParams[] calldata payloadSubmitParams + PayloadSubmitParams[] calldata payloadSubmitParams, + RequestMetadata calldata requestMetadata ) public returns (uint40 requestCount) { address appGateway = _checkAppGateways(payloadSubmitParams); @@ -96,6 +97,8 @@ abstract contract RequestHandler is WatcherPrecompileCore { requestParams[requestCount].payloadsRemaining = payloadSubmitParams.length; requestParams[requestCount].middleware = msg.sender; + requestMetadata[requestCount] = requestMetadata; + emit RequestSubmitted( msg.sender, requestCount, @@ -129,17 +132,17 @@ abstract contract RequestHandler is WatcherPrecompileCore { /// @notice Starts processing a request with a specified transmitter /// @param requestCount The request count to start processing - /// @param transmitter The address of the transmitter + /// @param winningBid The winning bid, contains fees, transmitter and extra data /// @dev This function initiates the processing of a request by a transmitter /// @dev It verifies that the caller is the middleware and that the request hasn't been started yet - function startProcessingRequest(uint40 requestCount, address transmitter) public { + function startProcessingRequest(uint40 requestCount, Bid memory winningBid) public { RequestParams storage r = requestParams[requestCount]; if (r.middleware != msg.sender) revert InvalidCaller(); if (r.transmitter != address(0)) revert AlreadyStarted(); if (r.currentBatchPayloadsLeft > 0) revert AlreadyStarted(); uint40 batchCount = r.payloadParamsArray[0].payloadHeader.getBatchCount(); - r.transmitter = transmitter; + r.transmitter = winningBid.transmitter; r.currentBatch = batchCount; _processBatch(requestCount, batchCount); diff --git a/contracts/protocol/watcherPrecompile/core/WatcherPrecompile.sol b/contracts/protocol/watcherPrecompile/core/WatcherPrecompile.sol index 3a91c754..27dc496b 100644 --- a/contracts/protocol/watcherPrecompile/core/WatcherPrecompile.sol +++ b/contracts/protocol/watcherPrecompile/core/WatcherPrecompile.sol @@ -112,12 +112,6 @@ contract WatcherPrecompile is RequestHandler { PayloadParams memory params_,` address transmitter_ ) external returns (bytes32) { - IFeesManager(addressResolver__.feesManager()).assignWatcherPrecompileFees( - evmxSlug, - params_.payloadHeader.getToken(), - watcherPrecompileLimits__.finalizeFees(params_.payloadHeader.getToken()), - msg.sender - ); return _finalize(params_, transmitter_); } @@ -208,15 +202,25 @@ contract WatcherPrecompile is RequestHandler { PayloadParams memory payloadParams = payloads[resolvedPromises_[i].payloadId]; address asyncPromise = payloadParams.asyncPromise; + uint40 requestCount = payloadParams.payloadHeader.getRequestCount(); + // todo: non trusted call if (asyncPromise != address(0)) { // Resolve each promise with its corresponding return data + + uint256 initialGas = gasleft(); bool success = IPromise(asyncPromise).markResolved( - payloadParams.payloadHeader.getRequestCount(), + requestCount, resolvedPromises_[i].payloadId, resolvedPromises_[i].returnData ); + uint256 gasUsed = initialGas - gasleft(); + _consumeFees( + requestCount, + gasUsed * tx.gasprice + ); + if (!success) { emit PromiseNotResolved(resolvedPromises_[i].payloadId, asyncPromise); continue; @@ -224,9 +228,7 @@ contract WatcherPrecompile is RequestHandler { } isPromiseExecuted[resolvedPromises_[i].payloadId] = true; - RequestParams storage requestParams_ = requestParams[ - payloadParams.payloadHeader.getRequestCount() - ]; + RequestParams storage requestParams_ = requestParams[requestCount]; requestParams_.currentBatchPayloadsLeft--; requestParams_.payloadsRemaining--; @@ -234,17 +236,12 @@ contract WatcherPrecompile is RequestHandler { if ( requestParams_.currentBatchPayloadsLeft == 0 && requestParams_.payloadsRemaining > 0 ) { - _processBatch( - payloadParams.payloadHeader.getRequestCount(), - ++requestParams_.currentBatch - ); + _processBatch(requestCount, ++requestParams_.currentBatch); } // if all payloads of a request are executed, finish the request if (requestParams_.payloadsRemaining == 0) { - IMiddleware(requestParams_.middleware).finishRequest( - payloadParams.payloadHeader.getRequestCount() - ); + IMiddleware(requestParams_.middleware).finishRequest(requestCount); } emit PromiseResolved(resolvedPromises_[i].payloadId, asyncPromise); } diff --git a/contracts/protocol/watcherPrecompile/core/WatcherPrecompileCore.sol b/contracts/protocol/watcherPrecompile/core/WatcherPrecompileCore.sol index 63e32618..70b109ad 100644 --- a/contracts/protocol/watcherPrecompile/core/WatcherPrecompileCore.sol +++ b/contracts/protocol/watcherPrecompile/core/WatcherPrecompileCore.sol @@ -33,6 +33,11 @@ abstract contract WatcherPrecompileCore is ) internal returns (bytes32 timeoutId) { if (delayInSeconds_ > maxTimeoutDelayInSeconds) revert TimeoutDelayTooLarge(); + _consumeFees( + requestCount_, + watcherPrecompileLimits__.scheduleFees(requestMetadata_.fees.feePoolToken) + ); + uint256 executeAt = block.timestamp + delayInSeconds_; timeoutId = _encodeTimeoutId(); @@ -74,6 +79,11 @@ abstract contract WatcherPrecompileCore is requestParams[params_.payloadHeader.getRequestCount()].middleware ); + _consumeFees( + params_.payloadHeader.getRequestCount(), + watcherPrecompileLimits__.finalizeFees(params_.payloadHeader.getChainSlug()) + ); + uint256 deadline = block.timestamp + expiryTime; payloads[params_.payloadId].deadline = deadline; payloads[params_.payloadId].finalizedTransmitter = transmitter_; @@ -109,6 +119,11 @@ abstract contract WatcherPrecompileCore is /// @param params_ The payload parameters for the query /// @dev This function sets up a query request and emits a QueryRequested event function _query(PayloadParams memory params_) internal { + _consumeFees( + params_.payloadHeader.getRequestCount(), + watcherPrecompileLimits__.queryFees(params_.payloadHeader.getChainSlug()) + ); + payloads[params_.payloadId].prevDigestsHash = _getPreviousDigestsHash( params_.payloadHeader.getBatchCount() ); @@ -239,6 +254,16 @@ abstract contract WatcherPrecompileCore is if (signer != owner()) revert InvalidWatcherSignature(); } + function _consumeFees(uint40 requestCount_, uint256 fees_) internal { + RequestMetadata memory requestMetadata_ = requestMetadata[requestCount_]; + IFeesManager(addressResolver__.feesManager()).assignWatcherPrecompileFees( + requestMetadata_.fees.feePoolChain, + requestMetadata_.fees.feePoolToken, + fees_, + requestCount_ + ); + } + /// @notice Gets the batch IDs for a request /// @param requestCount_ The request count to get the batch IDs for /// @return An array of batch IDs for the given request diff --git a/contracts/protocol/watcherPrecompile/core/WatcherPrecompileStorage.sol b/contracts/protocol/watcherPrecompile/core/WatcherPrecompileStorage.sol index d13ad022..ff40d67a 100644 --- a/contracts/protocol/watcherPrecompile/core/WatcherPrecompileStorage.sol +++ b/contracts/protocol/watcherPrecompile/core/WatcherPrecompileStorage.sol @@ -96,8 +96,12 @@ abstract contract WatcherPrecompileStorage is IWatcherPrecompile { // slot 64 IWatcherPrecompileConfig public watcherPrecompileConfig__; - // slots [65-114]: gap for future storage variables - uint256[50] _gap_after; + // slot 65 + /// @notice Mapping to store the request metadata for each request count + mapping(uint40 => RequestMetadata) public requestMetadata; + + // slots [66-114]: gap for future storage variables + uint256[49] _gap_after; // slots 115-165 (51) reserved for access control // slots 166-216 (51) reserved for addr resolver util From b9ca484232a546472ca98bd7c1be121b40580bd9 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Fri, 18 Apr 2025 15:01:02 +0530 Subject: [PATCH 2/3] feat: callback fees in finalize --- .../watcherPrecompile/core/WatcherPrecompile.sol | 10 ++-------- .../watcherPrecompile/core/WatcherPrecompileCore.sol | 5 ++++- .../core/WatcherPrecompileStorage.sol | 7 +++++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/contracts/protocol/watcherPrecompile/core/WatcherPrecompile.sol b/contracts/protocol/watcherPrecompile/core/WatcherPrecompile.sol index 27dc496b..5f11328b 100644 --- a/contracts/protocol/watcherPrecompile/core/WatcherPrecompile.sol +++ b/contracts/protocol/watcherPrecompile/core/WatcherPrecompile.sol @@ -42,6 +42,7 @@ contract WatcherPrecompile is RequestHandler { expiryTime = expiryTime_; evmxSlug = evmxSlug_; + callBackGasLimit = 5000000; } // ================== Timeout functions ================== @@ -206,21 +207,14 @@ contract WatcherPrecompile is RequestHandler { // todo: non trusted call if (asyncPromise != address(0)) { + // todo: limit the gas used for promise resolution // Resolve each promise with its corresponding return data - - uint256 initialGas = gasleft(); bool success = IPromise(asyncPromise).markResolved( requestCount, resolvedPromises_[i].payloadId, resolvedPromises_[i].returnData ); - uint256 gasUsed = initialGas - gasleft(); - _consumeFees( - requestCount, - gasUsed * tx.gasprice - ); - if (!success) { emit PromiseNotResolved(resolvedPromises_[i].payloadId, asyncPromise); continue; diff --git a/contracts/protocol/watcherPrecompile/core/WatcherPrecompileCore.sol b/contracts/protocol/watcherPrecompile/core/WatcherPrecompileCore.sol index 70b109ad..22f04acf 100644 --- a/contracts/protocol/watcherPrecompile/core/WatcherPrecompileCore.sol +++ b/contracts/protocol/watcherPrecompile/core/WatcherPrecompileCore.sol @@ -256,10 +256,13 @@ abstract contract WatcherPrecompileCore is function _consumeFees(uint40 requestCount_, uint256 fees_) internal { RequestMetadata memory requestMetadata_ = requestMetadata[requestCount_]; + + // for callbacks in all precompiles + uint256 feesToConsume = fees_ + tx.gasprice * callBackGasLimit; IFeesManager(addressResolver__.feesManager()).assignWatcherPrecompileFees( requestMetadata_.fees.feePoolChain, requestMetadata_.fees.feePoolToken, - fees_, + feesToConsume, requestCount_ ); } diff --git a/contracts/protocol/watcherPrecompile/core/WatcherPrecompileStorage.sol b/contracts/protocol/watcherPrecompile/core/WatcherPrecompileStorage.sol index ff40d67a..e28bf412 100644 --- a/contracts/protocol/watcherPrecompile/core/WatcherPrecompileStorage.sol +++ b/contracts/protocol/watcherPrecompile/core/WatcherPrecompileStorage.sol @@ -100,8 +100,11 @@ abstract contract WatcherPrecompileStorage is IWatcherPrecompile { /// @notice Mapping to store the request metadata for each request count mapping(uint40 => RequestMetadata) public requestMetadata; - // slots [66-114]: gap for future storage variables - uint256[49] _gap_after; + // slot 66 + uint256 public callBackGasLimit; + + // slots [67-114]: gap for future storage variables + uint256[48] _gap_after; // slots 115-165 (51) reserved for access control // slots 166-216 (51) reserved for addr resolver util From 2a7a8e8d8f90e2f25e0c243231fcfe853b2d2547 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Fri, 18 Apr 2025 15:48:02 +0530 Subject: [PATCH 3/3] fix: unblock and assign fees --- .../payload-delivery/AuctionManager.sol | 15 ++++++----- .../protocol/payload-delivery/FeesManager.sol | 26 ++++++++++++------- .../WatcherPrecompileLimits.sol | 17 ++++++++++++ .../core/WatcherPrecompile.sol | 1 - .../core/WatcherPrecompileCore.sol | 2 +- .../core/WatcherPrecompileStorage.sol | 3 --- 6 files changed, 43 insertions(+), 21 deletions(-) diff --git a/contracts/protocol/payload-delivery/AuctionManager.sol b/contracts/protocol/payload-delivery/AuctionManager.sol index d310343c..43b8e0fe 100644 --- a/contracts/protocol/payload-delivery/AuctionManager.sol +++ b/contracts/protocol/payload-delivery/AuctionManager.sol @@ -112,9 +112,12 @@ contract AuctionManager is ); if (!_hasRole(TRANSMITTER_ROLE, transmitter)) revert InvalidTransmitter(); + (uint256 watcherFees, uint256 transmitterFees) = getTransmitterMaxFeesRequired( + requestMetadata.fees.token, + requestCount_ + ); // check if the bid exceeds the max fees quoted by app gateway subtracting the watcher fees - if (fee > getTransmitterMaxFeesRequired(requestMetadata.fees.token, requestCount_)) - revert BidExceedsMaxFees(); + if (fee > transmitterFees) revert BidExceedsMaxFees(); // check if the bid is lower than the existing bid if ( @@ -141,10 +144,10 @@ contract AuctionManager is // block the fees IFeesManager(addressResolver__.feesManager()).blockFees( - requestMetadata.appGateway, + requestMetadata.consumeFrom, requestMetadata.fees, newBid, - watcherPrecompile__().getTotalFeesRequired(requestMetadata.fees.token, requestCount_), + watcherFees, requestCount_ ); @@ -210,7 +213,7 @@ contract AuctionManager is function getTransmitterMaxFeesRequired( address token_, uint40 requestCount_ - ) public view returns (uint256) { + ) public view returns (uint256, uint256) { // check if the bid is for this auction manager if (requestMetadata.auctionManager != address(this)) revert InvalidBid(); @@ -220,7 +223,7 @@ contract AuctionManager is // get the total fees required for the watcher precompile ops uint256 watcherFees = watcherPrecompile__().getTotalFeesRequired(token_, requestCount_); - return requestMetadata.fees.amount - watcherFees; + return (watcherFees, requestMetadata.fees.amount - watcherFees); } function _recoverSigner( diff --git a/contracts/protocol/payload-delivery/FeesManager.sol b/contracts/protocol/payload-delivery/FeesManager.sol index 53ac31bb..3443e54b 100644 --- a/contracts/protocol/payload-delivery/FeesManager.sol +++ b/contracts/protocol/payload-delivery/FeesManager.sol @@ -223,7 +223,7 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol /// @param requestCount_ The batch identifier /// @dev Only callable by delivery helper function blockFees( - address originAppGateway_, + address consumeFrom_, Fees memory feesGivenByApp_, Bid memory winningBid_, uint256 watcherFees_, @@ -232,11 +232,10 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol if (msg.sender != deliveryHelper__().getRequestMetadata(requestCount_).auctionManager) revert NotAuctionManager(); - address appGateway = _getCoreAppGateway(originAppGateway_); // Block fees uint256 availableFees = getAvailableFees( feesGivenByApp_.feePoolChain, - appGateway, + consumeFrom_, feesGivenByApp_.feePoolToken ); @@ -246,7 +245,7 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol uint256 feesNeeded = winningBid_.fee + watcherFees_; if (availableFees < feesNeeded) revert InsufficientFeesAvailable(); - TokenBalance storage tokenBalance = userFeeBalances[appGateway][ + TokenBalance storage tokenBalance = userFeeBalances[consumeFrom_][ feesGivenByApp_.feePoolChain ][feesGivenByApp_.feePoolToken]; @@ -260,6 +259,7 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol feePoolToken: feesGivenByApp_.feePoolToken, amount: feesNeeded }); + requestCountConsumeFrom[requestCount_] = consumeFrom_; emit FeesBlocked( requestCount_, @@ -274,23 +274,29 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol /// @param transmitter_ The address of the transmitter who executed the batch function unblockAndAssignFees( uint40 requestCount_, - address transmitter_, - address originAppGateway_ + address transmitter_ ) external override onlyDeliveryHelper { Fees memory fees = requestCountBlockedFees[requestCount_]; if (fees.amount == 0) return; - address appGateway = _getCoreAppGateway(originAppGateway_); - TokenBalance storage tokenBalance = userFeeBalances[appGateway][fees.feePoolChain][ + RequestMetadata memory requestMetadata = deliveryHelper__().getRequestMetadata( + requestCount_ + ); + + TokenBalance storage tokenBalance = userFeeBalances[consumeFrom][fees.feePoolChain][ fees.feePoolToken ]; + uint256 transmitterBid = requestMetadata.winningBid.fee; + uint256 remainingFees = fees.amount - transmitterBid; + // Unblock fees from deposit tokenBalance.blocked -= fees.amount; - tokenBalance.deposited -= fees.amount; + tokenBalance.deposited -= transmitterBid; + tokenBalance.deposited -= remainingFees; // Assign fees to transmitter - transmitterFees[transmitter_][fees.feePoolChain][fees.feePoolToken] += fees.amount; + transmitterFees[transmitter_][fees.feePoolChain][fees.feePoolToken] += transmitterBid; // Clean up storage delete requestCountBlockedFees[requestCount_]; diff --git a/contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol b/contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol index 1fdf374d..0ab07deb 100644 --- a/contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol +++ b/contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol @@ -47,6 +47,7 @@ contract WatcherPrecompileLimits is mapping(address => uint256) public queryFees; mapping(address => uint256) public finalizeFees; mapping(address => uint256) public scheduleFees; + mapping(address => uint256) public callBackFees; /// @notice Emitted when the default limit and rate per second are set event DefaultLimitAndRatePerSecondSet(uint256 defaultLimit, uint256 defaultRatePerSecond); @@ -196,6 +197,16 @@ contract WatcherPrecompileLimits is } } + function setCallBackFees( + address[] calldata tokens_, + uint256[] calldata amounts_ + ) external onlyOwner { + require(tokens_.length == amounts_.length, "Length mismatch"); + for (uint256 i = 0; i < tokens_.length; i++) { + callBackFees[tokens_[i]] = amounts_[i]; + } + } + function getTotalFeesRequired( address token_, uint40 requestCount_ @@ -205,9 +216,15 @@ contract WatcherPrecompileLimits is revert WatcherFeesNotSetForToken(token_); } + uint256 totalCallbacks = precompileCount[QUERY][requestCount_] + + precompileCount[FINALIZE][requestCount_] + + precompileCount[SCHEDULE][requestCount_]; + + totalFees += totalCallbacks * callBackFees[token_]; totalFees += precompileCount[QUERY][requestCount_] * queryFees[token_]; totalFees += precompileCount[FINALIZE][requestCount_] * finalizeFees[token_]; totalFees += precompileCount[SCHEDULE][requestCount_] * scheduleFees[token_]; + return totalFees; } } diff --git a/contracts/protocol/watcherPrecompile/core/WatcherPrecompile.sol b/contracts/protocol/watcherPrecompile/core/WatcherPrecompile.sol index 5f11328b..9e1ac974 100644 --- a/contracts/protocol/watcherPrecompile/core/WatcherPrecompile.sol +++ b/contracts/protocol/watcherPrecompile/core/WatcherPrecompile.sol @@ -42,7 +42,6 @@ contract WatcherPrecompile is RequestHandler { expiryTime = expiryTime_; evmxSlug = evmxSlug_; - callBackGasLimit = 5000000; } // ================== Timeout functions ================== diff --git a/contracts/protocol/watcherPrecompile/core/WatcherPrecompileCore.sol b/contracts/protocol/watcherPrecompile/core/WatcherPrecompileCore.sol index 22f04acf..d8cef4f0 100644 --- a/contracts/protocol/watcherPrecompile/core/WatcherPrecompileCore.sol +++ b/contracts/protocol/watcherPrecompile/core/WatcherPrecompileCore.sol @@ -258,7 +258,7 @@ abstract contract WatcherPrecompileCore is RequestMetadata memory requestMetadata_ = requestMetadata[requestCount_]; // for callbacks in all precompiles - uint256 feesToConsume = fees_ + tx.gasprice * callBackGasLimit; + uint256 feesToConsume = fees_ + watcherPrecompileLimits__().callBackFees(); IFeesManager(addressResolver__.feesManager()).assignWatcherPrecompileFees( requestMetadata_.fees.feePoolChain, requestMetadata_.fees.feePoolToken, diff --git a/contracts/protocol/watcherPrecompile/core/WatcherPrecompileStorage.sol b/contracts/protocol/watcherPrecompile/core/WatcherPrecompileStorage.sol index e28bf412..12dd3d53 100644 --- a/contracts/protocol/watcherPrecompile/core/WatcherPrecompileStorage.sol +++ b/contracts/protocol/watcherPrecompile/core/WatcherPrecompileStorage.sol @@ -100,9 +100,6 @@ abstract contract WatcherPrecompileStorage is IWatcherPrecompile { /// @notice Mapping to store the request metadata for each request count mapping(uint40 => RequestMetadata) public requestMetadata; - // slot 66 - uint256 public callBackGasLimit; - // slots [67-114]: gap for future storage variables uint256[48] _gap_after;