From 9c39bd07e01ec744f7396dd2914b0e5d3bce47c2 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Fri, 18 Apr 2025 17:57:54 +0530 Subject: [PATCH 1/7] fix: remove token and chain context from evmx --- .../payload-delivery/AuctionManager.sol | 16 +- .../protocol/payload-delivery/FeesManager.sol | 223 ++++++++---------- .../protocol/payload-delivery/FeesPlug.sol | 38 +-- 3 files changed, 105 insertions(+), 172 deletions(-) diff --git a/contracts/protocol/payload-delivery/AuctionManager.sol b/contracts/protocol/payload-delivery/AuctionManager.sol index 43b8e0fe..a27cbd3f 100644 --- a/contracts/protocol/payload-delivery/AuctionManager.sol +++ b/contracts/protocol/payload-delivery/AuctionManager.sol @@ -142,15 +142,6 @@ contract AuctionManager is _endAuction(requestCount_); } - // block the fees - IFeesManager(addressResolver__.feesManager()).blockFees( - requestMetadata.consumeFrom, - requestMetadata.fees, - newBid, - watcherFees, - requestCount_ - ); - emit BidPlaced(requestCount_, newBid); } @@ -168,6 +159,13 @@ contract AuctionManager is auctionClosed[requestCount_] = true; + // block the fees + IFeesManager(addressResolver__.feesManager()).blockFees( + requestMetadata.consumeFrom, + winningBid.fee, + requestCount_ + ); + // set the timeout for the bid expiration // useful in case a transmitter did bid but did not execute payloads watcherPrecompile__().setTimeout( diff --git a/contracts/protocol/payload-delivery/FeesManager.sol b/contracts/protocol/payload-delivery/FeesManager.sol index 9b8d96ea..39362e92 100644 --- a/contracts/protocol/payload-delivery/FeesManager.sol +++ b/contracts/protocol/payload-delivery/FeesManager.sol @@ -13,6 +13,16 @@ import {NotAuctionManager, InvalidWatcherSignature, NonceUsed} from "../utils/co import {Bid, Fees, CallType, Parallel, WriteFinality, TokenBalance, QueuePayloadParams, IsPlug, PayloadSubmitParams, RequestParams, RequestMetadata} from "../utils/common/Structs.sol"; abstract contract FeesManagerStorage is IFeesManager { + struct RequestFee { + uint256 blockedCredits; + address consumeFrom; + } + + struct UserCredits { + uint256 totalCredits; + uint256 blockedCredits; + } + // slots [0-49] reserved for gap uint256[50] _gap_before; @@ -25,34 +35,35 @@ abstract contract FeesManagerStorage is IFeesManager { // slot 52 bytes32 public sbType; - // slot 53 - /// @notice Master mapping tracking all fee information - /// @dev userAddress => chainSlug => TokenBalance - mapping(address => mapping(uint32 => TokenBalance)) public userFeeBalances; + // user credits + mapping(address => UserCredits) public userCredits; + + // token pool balances + // token address => chainSlug => amount + mapping(address => mapping(uint32 => uint256)) public tokenPoolBalances; + // user approved app gateways // userAddress => appGateway => isWhitelisted mapping(address => mapping(address => bool)) public isAppGatewayWhitelisted; // slot 54 - /// @notice Mapping to track blocked fees for each async id - /// @dev requestCount => Fees - mapping(uint40 => Fees) public requestCountBlockedFees; + /// @notice Mapping to track request credits details for each request count + /// @dev requestCount => RequestFee + mapping(uint40 => RequestFee) public requestCountCredits; // slot 55 - /// @notice Mapping to track fees to be distributed to transmitters - /// @dev transmitter => chainSlug => token => amount - mapping(address => mapping(uint32 => mapping(address => uint256))) public transmitterFees; + /// @notice Mapping to track credits to be distributed to transmitters + /// @dev transmitter => amount + mapping(address => uint256) public transmitterCredits; - // @dev chainSlug => token => amount - mapping(uint32 => mapping(address => uint256)) public watcherPrecompileFees; + // @dev amount + uint256 public watcherPrecompileCredits; // slot 56 /// @notice Mapping to track nonce to whether it has been used /// @dev signatureNonce => isNonceUsed mapping(uint256 => bool) public isNonceUsed; - mapping(uint40 => address) public requestCountConsumeFrom; - // slots [57-106] reserved for gap uint256[50] _gap_after; @@ -152,61 +163,41 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol } /// @notice Returns available (unblocked) fees for a gateway - /// @param chainSlug_ The chain identifier - /// @param appGateway_ The app gateway address - /// @param token_ The token address + /// @param consumeFrom_ The app gateway address /// @return The available fee amount - function getAvailableFees( - uint32 chainSlug_, - address consumeFrom_, - address token_ - ) public view returns (uint256) { - TokenBalance memory tokenBalance = userFeeBalances[consumeFrom_][chainSlug_][token_]; - if (tokenBalance.deposited == 0 || tokenBalance.deposited <= tokenBalance.blocked) return 0; - return tokenBalance.deposited - tokenBalance.blocked; + function getAvailableFees(address consumeFrom_) public view returns (uint256) { + UserCredits memory userCredit = userCredits[consumeFrom_]; + if (userCredit.totalCredits == 0 || userCredit.totalCredits <= userCredit.blockedCredits) + return 0; + return userCredit.totalCredits - userCredit.blockedCredits; } /// @notice Adds the fees deposited for an app gateway on a chain - /// @param chainSlug_ The chain identifier - /// @param originAppGateway_ The app gateway address - /// @param token_ The token address + /// @param consumeFrom_ The app gateway address /// @param amount_ The amount deposited function incrementFeesDeposited( - uint32 chainSlug_, - address originAppGateway_, - address token_, + address consumeFrom_, uint256 amount_, uint256 signatureNonce_, bytes memory signature_ ) external { - _isWatcherSignatureValid( - abi.encode(chainSlug_, originAppGateway_, token_, amount_), - signatureNonce_, - signature_ - ); + _isWatcherSignatureValid(abi.encode(consumeFrom_, amount_), signatureNonce_, signature_); - address appGateway = _getCoreAppGateway(originAppGateway_); + UserCredits storage userCredit = userCredits[consumeFrom_]; + userCredit.totalCredits += amount_; + tokenPoolBalances[token_][chainSlug_] += amount_; - TokenBalance storage tokenBalance = userFeeBalances[appGateway][chainSlug_][token_]; - tokenBalance.deposited += amount_; - emit FeesDepositedUpdated(chainSlug_, appGateway, token_, amount_); + emit FeesDepositedUpdated(consumeFrom_, amount_); } function isFeesEnough( - address originAppGateway_, + address appGateway_, address consumeFrom_, - Fees memory fees_ + uint256 amount_ ) external view returns (bool) { - address appGateway = _getCoreAppGateway(originAppGateway_); - address consumeFromCore = _getCoreAppGateway(consumeFrom_); - if (appGateway != consumeFromCore && !isAppGatewayWhitelisted[consumeFromCore][appGateway]) - return false; - uint256 availableFees = getAvailableFees( - fees_.feePoolChain, - consumeFrom_, - fees_.feePoolToken - ); - return availableFees >= fees_.amount; + address appGateway = _getCoreAppGateway(consumeFrom_); + if (!isAppGatewayWhitelisted[consumeFrom_][appGateway]) return false; + return getAvailableFees(consumeFrom_) >= amount_; } /// @notice Whitelists multiple app gateways for the caller @@ -218,55 +209,30 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol } /// @notice Blocks fees for a request count - /// @param originAppGateway_ The app gateway address - /// @param feesGivenByApp_ The fees data struct given by the app gateway + /// @param consumeFrom_ The fees payer address + /// @param totalFees_ The total fees to block /// @param requestCount_ The batch identifier /// @dev Only callable by delivery helper function blockFees( address consumeFrom_, - Fees memory feesGivenByApp_, - Bid memory winningBid_, - uint256 watcherFees_, + uint256 transmitterFees_, uint40 requestCount_ ) external { if (msg.sender != deliveryHelper__().getRequestMetadata(requestCount_).auctionManager) revert NotAuctionManager(); // Block fees - uint256 availableFees = getAvailableFees( - feesGivenByApp_.feePoolChain, - consumeFrom_, - feesGivenByApp_.feePoolToken - ); + if (getAvailableFees(consumeFrom_) < transmitterFees_) revert InsufficientFeesAvailable(); - if (requestCountBlockedFees[requestCount_].amount > 0) - availableFees += requestCountBlockedFees[requestCount_].amount; + UserCredits storage userCredit = userCredits[consumeFrom_]; + userCredit.blockedCredits += transmitterFees_; - uint256 feesNeeded = winningBid_.fee + watcherFees_; - if (availableFees < feesNeeded) revert InsufficientFeesAvailable(); - - TokenBalance storage tokenBalance = userFeeBalances[consumeFrom_][ - feesGivenByApp_.feePoolChain - ][feesGivenByApp_.feePoolToken]; - - tokenBalance.blocked = - tokenBalance.blocked + - feesNeeded - - requestCountBlockedFees[requestCount_].amount; - - requestCountBlockedFees[requestCount_] = Fees({ - feePoolChain: feesGivenByApp_.feePoolChain, - feePoolToken: feesGivenByApp_.feePoolToken, - amount: feesNeeded + requestCountCredits[requestCount_] = RequestFee({ + blockedCredits: transmitterFees_, + consumeFrom: consumeFrom_ }); - requestCountConsumeFrom[requestCount_] = consumeFrom_; - emit FeesBlocked( - requestCount_, - feesGivenByApp_.feePoolChain, - feesGivenByApp_.feePoolToken, - feesNeeded - ); + emit FeesBlocked(requestCount_, transmitterFees_); } /// @notice Unblocks fees after successful execution and assigns them to the transmitter @@ -276,45 +242,45 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol uint40 requestCount_, address transmitter_ ) external override onlyDeliveryHelper { - Fees memory fees = requestCountBlockedFees[requestCount_]; - if (fees.amount == 0) return; - - RequestMetadata memory requestMetadata = deliveryHelper__().getRequestMetadata( - requestCount_ - ); - - TokenBalance storage tokenBalance = userFeeBalances[consumeFrom][fees.feePoolChain][ - fees.feePoolToken - ]; + RequestFee memory requestFee = requestCountCredits[requestCount_]; + if (requestFee.blockedCredits == 0) return; - uint256 transmitterBid = requestMetadata.winningBid.fee; - uint256 remainingFees = fees.amount - transmitterBid; + uint256 fees = deliveryHelper__().getRequestMetadata(requestCount_).winningBid.fee; // Unblock fees from deposit - tokenBalance.blocked -= fees.amount; - tokenBalance.deposited -= transmitterBid; - tokenBalance.deposited -= remainingFees; + _useBlockedUserCredits(requestFee.consumeFrom, fees, fees); // Assign fees to transmitter - transmitterFees[transmitter_][fees.feePoolChain][fees.feePoolToken] += transmitterBid; + transmitterFees[transmitter_] += fees; // Clean up storage - delete requestCountBlockedFees[requestCount_]; - emit FeesUnblockedAndAssigned(requestCount_, transmitter_, fees.amount); + delete requestCountCredits[requestCount_]; + emit FeesUnblockedAndAssigned(requestCount_, transmitter_, fees); + } + + function _useBlockedUserCredits( + address consumeFrom_, + uint256 toBlock_, + uint256 toConsume_ + ) internal { + UserCredits storage userCredit = userCredits[consumeFrom_]; + userCredit.blockedCredits -= toBlock_; + userCredit.totalCredits -= toConsume_; } function assignWatcherPrecompileFees( - uint32 chainSlug_, - address token_, uint256 amount_, uint40 requestCount_ ) external onlyWatcherPrecompile { - Fees storage fees = requestCountBlockedFees[requestCount_]; - if (fees.amount == 0) revert NoFeesBlocked(); + RequestFee memory requestFee = requestCountCredits[requestCount_]; + if (requestFee.blockedCredits == 0) revert NoFeesBlocked(); + + // deduct the fees from the user + _useBlockedUserCredits(requestFee.consumeFrom, 0, amount_); - fees.amount -= amount_; - watcherPrecompileFees[chainSlug_][token_] += amount_; - emit WatcherPrecompileFeesAssigned(chainSlug_, token_, amount_, requestCount_); + // add the fees to the watcher precompile + watcherPrecompileCredits += amount_; + emit WatcherPrecompileFeesAssigned(requestCount_, amount_); } function unblockFees(uint40 requestCount_) external { @@ -327,19 +293,15 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol msg.sender != address(deliveryHelper__()) ) revert InvalidCaller(); - Fees memory fees = requestCountBlockedFees[requestCount_]; - if (fees.amount == 0) return; - - TokenBalance storage tokenBalance = userFeeBalances[requestMetadata.appGateway][ - fees.feePoolChain - ][fees.feePoolToken]; + RequestFee memory requestFee = requestCountCredits[requestCount_]; + if (requestFee.blockedCredits == 0) return; // Unblock fees from deposit - tokenBalance.blocked -= fees.amount; - tokenBalance.deposited += fees.amount; + UserCredits storage userCredit = userCredits[requestFee.consumeFrom]; + userCredit.blockedCredits -= requestFee.blockedCredits; - delete requestCountBlockedFees[requestCount_]; - emit FeesUnblocked(requestCount_, requestMetadata.appGateway); + delete requestCountCredits[requestCount_]; + emit FeesUnblocked(requestCount_, requestFee.consumeFrom); } /// @notice Withdraws fees to a specified receiver @@ -349,21 +311,23 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol function withdrawTransmitterFees( uint32 chainSlug_, address token_, - address receiver_ + address receiver_, + uint256 amount_ ) external returns (uint40 requestCount) { address transmitter = msg.sender; // Get total fees for the transmitter in given chain and token - uint256 totalFees = transmitterFees[transmitter][chainSlug_][token_]; - if (totalFees == 0) revert NoFeesForTransmitter(); + uint256 totalFees = transmitterFees[transmitter]; + if (totalFees >= amount_) revert InsufficientFeesAvailable(); // Clean up storage - transmitterFees[transmitter][chainSlug_][token_] = 0; + transmitterFees[transmitter] -= amount_; + tokenPoolBalances[token_][chainSlug_] -= amount_; // Create fee distribution payload bytes32 feesId = _encodeFeesId(feesCounter++); bytes memory payload = abi.encodeCall( IFeesPlug.distributeFee, - (token_, totalFees, receiver_, feesId) + (token_, amount_, receiver_, feesId) ); // finalize for plug contract @@ -388,11 +352,10 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol address source = _getCoreAppGateway(originAppGatewayOrUser_); // Check if amount is available in fees plug - uint256 availableAmount = getAvailableFees(chainSlug_, source, token_); + uint256 availableAmount = getAvailableFees(source); if (availableAmount < amount_) revert InsufficientFeesAvailable(); - TokenBalance storage tokenBalance = userFeeBalances[source][chainSlug_][token_]; - tokenBalance.deposited -= amount_; + tokenPoolBalances[token_][chainSlug_] -= amount_; // Add it to the queue and submit request _queue(chainSlug_, abi.encodeCall(IFeesPlug.withdrawFees, (token_, amount_, receiver_))); diff --git a/contracts/protocol/payload-delivery/FeesPlug.sol b/contracts/protocol/payload-delivery/FeesPlug.sol index 773ceb7d..f21826ab 100644 --- a/contracts/protocol/payload-delivery/FeesPlug.sol +++ b/contracts/protocol/payload-delivery/FeesPlug.sol @@ -50,9 +50,6 @@ contract FeesPlug is IFeesPlug, PlugBase, AccessControl { constructor(address socket_, address owner_) { _setSocket(socket_); _initializeOwner(owner_); - - // ETH is whitelisted by default - whitelistedTokens[ETH_ADDRESS] = true; } /// @notice Distributes fees to the transmitter @@ -88,11 +85,7 @@ contract FeesPlug is IFeesPlug, PlugBase, AccessControl { emit FeesWithdrawn(token_, amount_, receiver_); } - function depositToFee( - address token_, - uint256 amount_, - address receiver_ - ) external payable override { + function depositToFee(address token_, uint256 amount_, address receiver_) external override { _deposit(token_, receiver_, amount_, 0); } @@ -100,17 +93,13 @@ contract FeesPlug is IFeesPlug, PlugBase, AccessControl { address token_, uint256 amount_, address receiver_ - ) external payable override { + ) external override { uint256 nativeAmount_ = amount_ / 10; uint256 feeAmount_ = amount_ - nativeAmount_; _deposit(token_, receiver_, feeAmount_, nativeAmount_); } - function depositToNative( - address token_, - uint256 amount_, - address receiver_ - ) external payable override { + function depositToNative(address token_, uint256 amount_, address receiver_) external override { _deposit(token_, receiver_, 0, amount_); } @@ -127,19 +116,9 @@ contract FeesPlug is IFeesPlug, PlugBase, AccessControl { ) internal override { uint256 totalAmount_ = feeAmount_ + nativeAmount_; if (!whitelistedTokens[token_]) revert TokenNotWhitelisted(token_); - - if (token_ == ETH_ADDRESS) { - if (msg.value != totalAmount_) revert InvalidDepositAmount(); - } else { - if (token_.code.length == 0) revert InvalidTokenAddress(); - } + if (token_.code.length == 0) revert InvalidTokenAddress(); balanceOf[token_] += totalAmount_; - - if (token_ != ETH_ADDRESS) { - SafeTransferLib.safeTransferFrom(token_, msg.sender, address(this), totalAmount_); - } - emit FeesDeposited(receiver_, token_, feeAmount_, nativeAmount_); } @@ -148,11 +127,7 @@ contract FeesPlug is IFeesPlug, PlugBase, AccessControl { /// @param amount_ The amount /// @param receiver_ The receiver address function _transferTokens(address token_, uint256 amount_, address receiver_) internal { - if (token_ == ETH_ADDRESS) { - SafeTransferLib.forceSafeTransferETH(receiver_, amount_); - } else { - SafeTransferLib.safeTransfer(token_, receiver_, amount_); - } + SafeTransferLib.safeTransfer(token_, receiver_, amount_); } function connectSocket( @@ -173,7 +148,6 @@ contract FeesPlug is IFeesPlug, PlugBase, AccessControl { /// @notice Removes a token from the whitelist /// @param token_ The token address to remove function removeTokenFromWhitelist(address token_) external onlyOwner { - if (token_ == ETH_ADDRESS) revert(); // Cannot remove ETH from whitelist whitelistedTokens[token_] = false; emit TokenRemovedFromWhitelist(token_); } @@ -192,6 +166,4 @@ contract FeesPlug is IFeesPlug, PlugBase, AccessControl { ) external onlyRole(RESCUE_ROLE) { RescueFundsLib._rescueFunds(token_, rescueTo_, amount_); } - - receive() external payable {} } From e38a3952cc34e1dd0615e5e4385ae288850d8a6b Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Fri, 18 Apr 2025 17:59:49 +0530 Subject: [PATCH 2/7] fix: remove old structs --- .../protocol/payload-delivery/FeesManager.sol | 11 +---------- contracts/protocol/utils/common/Structs.sol | 18 ++++++++---------- 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/contracts/protocol/payload-delivery/FeesManager.sol b/contracts/protocol/payload-delivery/FeesManager.sol index 39362e92..c47232fe 100644 --- a/contracts/protocol/payload-delivery/FeesManager.sol +++ b/contracts/protocol/payload-delivery/FeesManager.sol @@ -10,18 +10,9 @@ import {IFeesManager} from "../../interfaces/IFeesManager.sol"; import {AddressResolverUtil} from "../utils/AddressResolverUtil.sol"; import {NotAuctionManager, InvalidWatcherSignature, NonceUsed} from "../utils/common/Errors.sol"; -import {Bid, Fees, CallType, Parallel, WriteFinality, TokenBalance, QueuePayloadParams, IsPlug, PayloadSubmitParams, RequestParams, RequestMetadata} from "../utils/common/Structs.sol"; +import {Bid, CallType, Parallel, WriteFinality, QueuePayloadParams, IsPlug, PayloadSubmitParams, RequestMetadata, RequestFee, UserCredits} from "../utils/common/Structs.sol"; abstract contract FeesManagerStorage is IFeesManager { - struct RequestFee { - uint256 blockedCredits; - address consumeFrom; - } - - struct UserCredits { - uint256 totalCredits; - uint256 blockedCredits; - } // slots [0-49] reserved for gap uint256[50] _gap_before; diff --git a/contracts/protocol/utils/common/Structs.sol b/contracts/protocol/utils/common/Structs.sol index 32170560..c4f00ca1 100644 --- a/contracts/protocol/utils/common/Structs.sol +++ b/contracts/protocol/utils/common/Structs.sol @@ -119,10 +119,14 @@ struct OverrideParams { } // FM: -struct Fees { - uint32 feePoolChain; - address feePoolToken; - uint256 amount; +struct RequestFee { + uint256 blockedCredits; + address consumeFrom; +} + +struct UserCredits { + uint256 totalCredits; + uint256 blockedCredits; } // digest: @@ -237,9 +241,3 @@ struct ExecuteParams { bytes32 prevDigestsHash; // should be id? hash of hashes address switchboard; } - -/// @notice Struct containing fee amounts and status -struct TokenBalance { - uint256 deposited; // Amount deposited - uint256 blocked; // Amount blocked -} From 6a399f0e4726ccaf693a54dc53d1cb8aa3a3676a Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Sat, 19 Apr 2025 05:17:50 +0530 Subject: [PATCH 3/7] fix: wip build fix --- contracts/base/AppGatewayBase.sol | 12 +++++------ contracts/interfaces/IAppGateway.sol | 2 +- contracts/interfaces/IAuctionManager.sol | 2 +- contracts/interfaces/IFeesManager.sol | 6 +++--- contracts/interfaces/IMiddleware.sol | 8 +++---- .../protocol/payload-delivery/FeesManager.sol | 8 +++---- .../protocol/payload-delivery/FeesPlug.sol | 2 +- .../app-gateway/DeliveryUtils.sol | 3 ++- .../app-gateway/FeesHelpers.sol | 6 +++--- .../app-gateway/RequestQueue.sol | 19 ++++++++++------- contracts/protocol/utils/FeesPlugin.sol | 21 ------------------- contracts/protocol/utils/common/Structs.sol | 2 +- .../core/WatcherPrecompile.sol | 2 +- script/counter/DeployEVMxCounterApp.s.sol | 7 +------ script/counter/SetFees.s.sol | 7 +------ script/helpers/AppGatewayFeeBalance.s.sol | 1 - script/helpers/PayFeesInArbitrumETH.s.sol | 1 - .../counter/CounterAppGateway.sol | 4 ++-- .../super-token/SuperTokenAppGateway.sol | 2 +- 19 files changed, 43 insertions(+), 72 deletions(-) delete mode 100644 contracts/protocol/utils/FeesPlugin.sol diff --git a/contracts/base/AppGatewayBase.sol b/contracts/base/AppGatewayBase.sol index 82422aae..abd4996d 100644 --- a/contracts/base/AppGatewayBase.sol +++ b/contracts/base/AppGatewayBase.sol @@ -7,19 +7,19 @@ import "../interfaces/IForwarder.sol"; import "../interfaces/IMiddleware.sol"; import "../interfaces/IPromise.sol"; -import {FeesPlugin} from "../protocol/utils/FeesPlugin.sol"; import {InvalidPromise, FeesNotSet, AsyncModifierNotUsed} from "../protocol/utils/common/Errors.sol"; import {FAST} from "../protocol/utils/common/Constants.sol"; /// @title AppGatewayBase /// @notice Abstract contract for the app gateway /// @dev This contract contains helpers for contract deployment, overrides, hooks and request processing -abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway, FeesPlugin { +abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { OverrideParams public overrideParams; bool public isAsyncModifierSet; address public auctionManager; bytes32 public sbType; bytes public onCompleteData; + uint256 public fees; mapping(address => bool) public isValidPromise; mapping(bytes32 => mapping(uint32 => address)) public override forwarderAddresses; @@ -29,10 +29,10 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway, FeesPlugin modifier async(bytes memory feesApprovalData_) { _preAsync(); _; - _postAsync(); + _postAsync(feesApprovalData_); } - function _postAsync() internal { + function _postAsync(bytes memory feesApprovalData_) internal { isAsyncModifierSet = false; // todo: cache the feesApprovalData for next async in same request @@ -204,7 +204,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway, FeesPlugin Read isReadCall_, Parallel isParallelCall_, uint256 gasLimit_, - Fees memory fees_ + uint256 fees_ ) internal { overrideParams.isReadCall = isReadCall_; overrideParams.isParallelCall = isParallelCall_; @@ -285,7 +285,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway, FeesPlugin /// @notice Sets fees overrides /// @param fees_ The fees configuration - function _setOverrides(Fees memory fees_) internal { + function _setOverrides(uint256 fees_) internal { fees = fees_; } diff --git a/contracts/interfaces/IAppGateway.sol b/contracts/interfaces/IAppGateway.sol index 8997710b..c8e9fd73 100644 --- a/contracts/interfaces/IAppGateway.sol +++ b/contracts/interfaces/IAppGateway.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import {Fees, Read, Parallel, QueuePayloadParams, OverrideParams, CallType, WriteFinality, PayloadParams} from "../protocol/utils/common/Structs.sol"; +import {Read, Parallel, QueuePayloadParams, OverrideParams, CallType, WriteFinality, PayloadParams} from "../protocol/utils/common/Structs.sol"; /// @title IAppGateway /// @notice Interface for the app gateway diff --git a/contracts/interfaces/IAuctionManager.sol b/contracts/interfaces/IAuctionManager.sol index 45344b7a..a67f0200 100644 --- a/contracts/interfaces/IAuctionManager.sol +++ b/contracts/interfaces/IAuctionManager.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import {Bid, Fees, RequestMetadata, RequestParams} from "../protocol/utils/common/Structs.sol"; +import {Bid, RequestMetadata, RequestParams} from "../protocol/utils/common/Structs.sol"; interface IAuctionManager { /// @notice Bids for an auction diff --git a/contracts/interfaces/IFeesManager.sol b/contracts/interfaces/IFeesManager.sol index 80953ba7..a6c90520 100644 --- a/contracts/interfaces/IFeesManager.sol +++ b/contracts/interfaces/IFeesManager.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import {Fees, Bid, QueuePayloadParams} from "../protocol/utils/common/Structs.sol"; +import {Bid, QueuePayloadParams} from "../protocol/utils/common/Structs.sol"; interface IFeesManager { function blockFees( address appGateway_, - Fees memory fees_, + uint256 fees_, Bid memory winningBid_, uint40 requestCount_ ) external; @@ -16,7 +16,7 @@ interface IFeesManager { function isFeesEnough( address appGateway_, address consumeFrom_, - Fees memory fees_ + uint256 fees_ ) external view returns (bool); function unblockAndAssignFees( diff --git a/contracts/interfaces/IMiddleware.sol b/contracts/interfaces/IMiddleware.sol index ce949529..46a2410d 100644 --- a/contracts/interfaces/IMiddleware.sol +++ b/contracts/interfaces/IMiddleware.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import {PayloadSubmitParams, QueuePayloadParams, Bid, Fees, WriteFinality, CallType, Parallel, IsPlug, RequestMetadata, } from "../protocol/utils/common/Structs.sol"; +import {PayloadSubmitParams, QueuePayloadParams, Bid, WriteFinality, CallType, Parallel, IsPlug, RequestMetadata, RequestFee} from "../protocol/utils/common/Structs.sol"; /// @title IMiddleware /// @notice Interface for the Middleware contract @@ -29,7 +29,7 @@ interface IMiddleware { /// @param onCompleteData_ The data to be passed to the onComplete callback /// @return requestCount The request id function batch( - Fees memory fees_, + uint256 fees_, address auctionManager_, bytes memory feesApprovalData_, bytes memory onCompleteData_ @@ -48,7 +48,7 @@ interface IMiddleware { uint256 amount_, address receiver_, address auctionManager_, - Fees memory fees_ + uint256 fees_ ) external returns (uint40); /// @notice Cancels a request @@ -66,7 +66,7 @@ interface IMiddleware { function startRequestProcessing(uint40 requestCount_, Bid memory winningBid_) external; /// @notice Returns the fees for a request - function getFees(uint40 requestCount_) external view returns (Fees memory); + function getFees(uint40 requestCount_) external view returns (uint256); /// @notice Finishes a request by assigning fees and calling the onComplete callback /// @param requestCount_ The request id diff --git a/contracts/protocol/payload-delivery/FeesManager.sol b/contracts/protocol/payload-delivery/FeesManager.sol index c47232fe..0e1bc855 100644 --- a/contracts/protocol/payload-delivery/FeesManager.sol +++ b/contracts/protocol/payload-delivery/FeesManager.sol @@ -13,7 +13,6 @@ import {NotAuctionManager, InvalidWatcherSignature, NonceUsed} from "../utils/co import {Bid, CallType, Parallel, WriteFinality, QueuePayloadParams, IsPlug, PayloadSubmitParams, RequestMetadata, RequestFee, UserCredits} from "../utils/common/Structs.sol"; abstract contract FeesManagerStorage is IFeesManager { - // slots [0-49] reserved for gap uint256[50] _gap_before; @@ -201,7 +200,7 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol /// @notice Blocks fees for a request count /// @param consumeFrom_ The fees payer address - /// @param totalFees_ The total fees to block + /// @param transmitterFees_ The total fees to block /// @param requestCount_ The batch identifier /// @dev Only callable by delivery helper function blockFees( @@ -327,7 +326,7 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol /// @notice Withdraws funds to a specified receiver /// @dev This function is used to withdraw fees from the fees plug - /// @param originAppGateway_ The address of the app gateway + /// @param originAppGatewayOrUser_ The address of the app gateway /// @param chainSlug_ The chain identifier /// @param token_ The address of the token /// @param amount_ The amount of tokens to withdraw @@ -378,9 +377,10 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol appGateway: address(this), auctionManager: address(0), feesApprovalData: bytes(""), - fees: Fees({token: token_, amount: amount_}), + fees: amount_, winningBid: Bid({transmitter: transmitter_, fee: 0, extraData: new bytes(0)}) }); + requestCount = watcherPrecompile__().submitRequest( payloadSubmitParamsArray, requestMetadata diff --git a/contracts/protocol/payload-delivery/FeesPlug.sol b/contracts/protocol/payload-delivery/FeesPlug.sol index f21826ab..2f5bc16f 100644 --- a/contracts/protocol/payload-delivery/FeesPlug.sol +++ b/contracts/protocol/payload-delivery/FeesPlug.sol @@ -107,7 +107,7 @@ contract FeesPlug is IFeesPlug, PlugBase, AccessControl { /// @param token_ The token address /// @param feeAmount_ The amount of fees /// @param nativeAmount_ The amount of native tokens - /// @param appGateway_ The app gateway address + /// @param receiver_ The receiver address function _deposit( address token_, address receiver_, diff --git a/contracts/protocol/payload-delivery/app-gateway/DeliveryUtils.sol b/contracts/protocol/payload-delivery/app-gateway/DeliveryUtils.sol index 8fa29c14..38fcecc9 100644 --- a/contracts/protocol/payload-delivery/app-gateway/DeliveryUtils.sol +++ b/contracts/protocol/payload-delivery/app-gateway/DeliveryUtils.sol @@ -39,10 +39,11 @@ abstract contract DeliveryUtils is uint40 indexed requestCount, address indexed appGateway, PayloadSubmitParams[] payloadSubmitParams, - Fees fees, + uint256 fees, address auctionManager, bool onlyReadRequests ); + /// @notice Emitted when fees are increased event FeesIncreased( address indexed appGateway, diff --git a/contracts/protocol/payload-delivery/app-gateway/FeesHelpers.sol b/contracts/protocol/payload-delivery/app-gateway/FeesHelpers.sol index 1c59ac64..ccda6afe 100644 --- a/contracts/protocol/payload-delivery/app-gateway/FeesHelpers.sol +++ b/contracts/protocol/payload-delivery/app-gateway/FeesHelpers.sol @@ -37,7 +37,7 @@ abstract contract FeesHelpers is RequestQueue { uint256 amount_, address receiver_, address auctionManager_, - Fees memory fees_ + uint256 fees_ ) external returns (uint40) { IFeesManager(addressResolver__.feesManager()).withdrawFees( msg.sender, @@ -53,7 +53,7 @@ abstract contract FeesHelpers is RequestQueue { /// @notice Returns the fees for a request /// @param requestCount_ The ID of the request /// @return fees The fees data - function getFees(uint40 requestCount_) external view returns (Fees memory) { - return requests[requestCount_].fees; + function getFees(uint40 requestCount_) external view returns (uint256) { + return requests[requestCount_].fees.amount; } } diff --git a/contracts/protocol/payload-delivery/app-gateway/RequestQueue.sol b/contracts/protocol/payload-delivery/app-gateway/RequestQueue.sol index be9cabf7..12d9d458 100644 --- a/contracts/protocol/payload-delivery/app-gateway/RequestQueue.sol +++ b/contracts/protocol/payload-delivery/app-gateway/RequestQueue.sol @@ -24,19 +24,19 @@ abstract contract RequestQueue is DeliveryUtils { /// @param auctionManager_ The auction manager address /// @return requestCount The ID of the batch function batch( - Fees memory fees_, + uint256 fees_, address auctionManager_, bytes memory feesApprovalData_, bytes memory onCompleteData_ ) external returns (uint40 requestCount) { address appGateway = _getCoreAppGateway(msg.sender); - return _batch(appGateway, auctionManager_, feesApprovalData_, onCompleteData_); + return _batch(appGateway, auctionManager_, fees_, feesApprovalData_, onCompleteData_); } function _checkBatch( address appGateway_, bytes memory feesApprovalData_, - Fees memory fees_ + uint256 fees_ ) internal view { if (queuePayloadParams.length > REQUEST_PAYLOAD_COUNT_LIMIT) revert RequestPayloadCountLimitExceeded(); @@ -64,7 +64,7 @@ abstract contract RequestQueue is DeliveryUtils { function _batch( address appGateway_, address auctionManager_, - Fees memory fees_, + uint256 fees_, bytes memory feesApprovalData_, bytes memory onCompleteData_ ) internal returns (uint40 requestCount) { @@ -89,7 +89,10 @@ abstract contract RequestQueue is DeliveryUtils { }); // process and submit the queue of payloads to watcher precompile - requestCount = watcherPrecompile__().submitRequest(payloadSubmitParamsArray, requestMetadata); + requestCount = watcherPrecompile__().submitRequest( + payloadSubmitParamsArray, + requestMetadata + ); requests[requestCount] = requestMetadata; // send query directly if request contains only reads @@ -98,14 +101,14 @@ abstract contract RequestQueue is DeliveryUtils { watcherPrecompile__().startProcessingRequest(requestCount, address(0)); // to save extra calls from transmitter - uint256 maxTransmitterFees = fees_.amount - - watcherPrecompile__().getTotalFeesRequired(fees_.token, requestCount); + uint256 maxTransmitterFees = fees_ - + watcherPrecompile__().getTotalFeesRequired(requestCount); emit PayloadSubmitted( requestCount, appGateway_, payloadSubmitParamsArray, - Fees({token: fees_.token, amount: fees_.amount - maxTransmitterFees}), + fees_ - maxTransmitterFees, auctionManager_, onlyReadRequests ); diff --git a/contracts/protocol/utils/FeesPlugin.sol b/contracts/protocol/utils/FeesPlugin.sol deleted file mode 100644 index c78bc932..00000000 --- a/contracts/protocol/utils/FeesPlugin.sol +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity ^0.8.21; - -import {Fees} from "../utils/common/Structs.sol"; - -/// @title FeesPlugin -/// @notice Abstract contract for managing fee configurations -/// @dev Provides base functionality for fee management in the system -abstract contract FeesPlugin { - /// @notice Storage for the current fee configuration - /// @dev Contains fee parameters like chain slug, token address, and amount - Fees public fees; - - /// @notice Retrieves the current fee configuration - /// @return Current fee configuration struct - /// @dev Public view function accessible to any caller - /// @dev Used by external contracts to verify fee parameters - function getFees() public view returns (Fees memory) { - return fees; - } -} diff --git a/contracts/protocol/utils/common/Structs.sol b/contracts/protocol/utils/common/Structs.sol index c4f00ca1..36c73bb0 100644 --- a/contracts/protocol/utils/common/Structs.sol +++ b/contracts/protocol/utils/common/Structs.sol @@ -219,7 +219,7 @@ struct RequestParams { struct RequestMetadata { address appGateway; address auctionManager; - Fees fees; + uint256 fees; Bid winningBid; bytes onCompleteData; bool onlyReadRequests; diff --git a/contracts/protocol/watcherPrecompile/core/WatcherPrecompile.sol b/contracts/protocol/watcherPrecompile/core/WatcherPrecompile.sol index 78f6f102..40f1b13d 100644 --- a/contracts/protocol/watcherPrecompile/core/WatcherPrecompile.sol +++ b/contracts/protocol/watcherPrecompile/core/WatcherPrecompile.sol @@ -109,7 +109,7 @@ contract WatcherPrecompile is RequestHandler { /// @return The digest hash of the finalized payload /// @dev This function finalizes a payload request and requests the watcher to release the proofs function finalize( - PayloadParams memory params_,` + PayloadParams memory params_, address transmitter_ ) external returns (bytes32) { return _finalize(params_, transmitter_); diff --git a/script/counter/DeployEVMxCounterApp.s.sol b/script/counter/DeployEVMxCounterApp.s.sol index 9e0cbee8..85755639 100644 --- a/script/counter/DeployEVMxCounterApp.s.sol +++ b/script/counter/DeployEVMxCounterApp.s.sol @@ -4,7 +4,6 @@ pragma solidity ^0.8.21; import {Script} from "forge-std/Script.sol"; import {console} from "forge-std/console.sol"; import {CounterAppGateway} from "../../test/apps/app-gateways/counter/CounterAppGateway.sol"; -import {Fees} from "../../contracts/protocol/utils/common/Structs.sol"; import {ETH_ADDRESS} from "../../contracts/protocol/utils/common/Constants.sol"; // source .env && forge script script/counter/deployEVMxCounterApp.s.sol --broadcast --skip-simulation --legacy --gas-price 0 @@ -18,11 +17,7 @@ contract CounterDeploy is Script { vm.startBroadcast(deployerPrivateKey); // Setting fee payment on Arbitrum Sepolia - Fees memory fees = Fees({ - feePoolChain: 421614, - feePoolToken: ETH_ADDRESS, - amount: 0.00001 ether - }); + uint256 fees = 0.00001 ether; CounterAppGateway gateway = new CounterAppGateway(addressResolver, fees); diff --git a/script/counter/SetFees.s.sol b/script/counter/SetFees.s.sol index c97a2b0b..e48d9a73 100644 --- a/script/counter/SetFees.s.sol +++ b/script/counter/SetFees.s.sol @@ -5,7 +5,6 @@ import {Script} from "forge-std/Script.sol"; import {console} from "forge-std/console.sol"; import {ETH_ADDRESS} from "../../contracts/protocol/utils/common/Constants.sol"; import {CounterAppGateway} from "../../test/apps/app-gateways/counter/CounterAppGateway.sol"; -import {Fees} from "../../contracts/protocol/utils/common/Structs.sol"; // source .env && forge script script/counter/DeployCounterOnchain.s.sol --broadcast --skip-simulation --legacy --gas-price 0 contract CounterSetFees is Script { @@ -22,11 +21,7 @@ contract CounterSetFees is Script { console.log("Setting fees..."); // Setting fee payment on Arbitrum Sepolia - Fees memory fees = Fees({ - feePoolChain: 421614, - feePoolToken: ETH_ADDRESS, - amount: 0.00001 ether - }); + uint256 fees = 0.00001 ether; appGateway.setFees(fees); } } diff --git a/script/helpers/AppGatewayFeeBalance.s.sol b/script/helpers/AppGatewayFeeBalance.s.sol index 9bf7c2c9..a1faade9 100644 --- a/script/helpers/AppGatewayFeeBalance.s.sol +++ b/script/helpers/AppGatewayFeeBalance.s.sol @@ -4,7 +4,6 @@ pragma solidity ^0.8.21; import {Script} from "forge-std/Script.sol"; import {console} from "forge-std/console.sol"; import {FeesManager} from "../../contracts/protocol/payload-delivery/FeesManager.sol"; -import {Fees} from "../../contracts/protocol/utils/common/Structs.sol"; import {ETH_ADDRESS} from "../../contracts/protocol/utils/common/Constants.sol"; contract CheckDepositedFees is Script { diff --git a/script/helpers/PayFeesInArbitrumETH.s.sol b/script/helpers/PayFeesInArbitrumETH.s.sol index edb8b2fd..6fbd7164 100644 --- a/script/helpers/PayFeesInArbitrumETH.s.sol +++ b/script/helpers/PayFeesInArbitrumETH.s.sol @@ -4,7 +4,6 @@ pragma solidity ^0.8.21; import {Script} from "forge-std/Script.sol"; import {console} from "forge-std/console.sol"; import {FeesPlug} from "../../contracts/protocol/payload-delivery/FeesPlug.sol"; -import {Fees} from "../../contracts/protocol/utils/common/Structs.sol"; import {ETH_ADDRESS} from "../../contracts/protocol/utils/common/Constants.sol"; // source .env && forge script script/helpers/PayFeesInArbitrumETH.s.sol --broadcast --skip-simulation diff --git a/test/apps/app-gateways/counter/CounterAppGateway.sol b/test/apps/app-gateways/counter/CounterAppGateway.sol index a27b2db1..a7b9561b 100644 --- a/test/apps/app-gateways/counter/CounterAppGateway.sol +++ b/test/apps/app-gateways/counter/CounterAppGateway.sol @@ -17,7 +17,7 @@ contract CounterAppGateway is AppGatewayBase, Ownable { uint256 public optCounter; event TimeoutResolved(uint256 creationTimestamp, uint256 executionTimestamp); - constructor(address addressResolver_, Fees memory fees_) AppGatewayBase(addressResolver_) { + constructor(address addressResolver_, uint256 fees_) AppGatewayBase(addressResolver_) { creationCodeWithArgs[counter] = abi.encodePacked(type(Counter).creationCode); creationCodeWithArgs[counter1] = abi.encodePacked(type(Counter).creationCode); _setOverrides(fees_); @@ -120,7 +120,7 @@ contract CounterAppGateway is AppGatewayBase, Ownable { } // UTILS - function setFees(Fees memory fees_) public { + function setFees(uint256 fees_) public { fees = fees_; } diff --git a/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol b/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol index 98488499..58846bc6 100644 --- a/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol +++ b/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol @@ -29,7 +29,7 @@ contract SuperTokenAppGateway is AppGatewayBase, Ownable { constructor( address addressResolver_, address owner_, - Fees memory fees_, + uint256 fees_, ConstructorParams memory params_ ) AppGatewayBase(addressResolver_) { creationCodeWithArgs[superToken] = abi.encodePacked( From fceb0df2fcb223e6af0cbbf4acd1fc2e93476778 Mon Sep 17 00:00:00 2001 From: Akash Date: Mon, 21 Apr 2025 11:42:29 +0530 Subject: [PATCH 4/7] fix: build, wip --- FunctionSignatures.md | 2 +- contracts/base/AppGatewayBase.sol | 26 +- contracts/interfaces/IFeesManager.sol | 29 +- contracts/interfaces/IFeesPlug.sol | 6 +- contracts/interfaces/IMiddleware.sol | 2 +- contracts/interfaces/IWatcherPrecompile.sol | 5 +- .../interfaces/IWatcherPrecompileLimits.sol | 20 +- .../payload-delivery/AuctionManager.sol | 35 +-- .../protocol/payload-delivery/FeesManager.sol | 249 +++++++++++------- .../protocol/payload-delivery/FeesPlug.sol | 2 +- .../app-gateway/DeliveryHelper.sol | 8 +- .../app-gateway/FeesHelpers.sol | 6 +- .../app-gateway/RequestQueue.sol | 36 +-- .../protocol/utils/AddressResolverUtil.sol | 1 + contracts/protocol/utils/common/Constants.sol | 1 + contracts/protocol/utils/common/Structs.sol | 16 +- .../WatcherPrecompileLimits.sol | 84 +++--- .../watcherPrecompile/core/RequestHandler.sol | 23 +- .../core/WatcherPrecompile.sol | 7 +- .../core/WatcherPrecompileCore.sol | 38 +-- test/DeliveryHelper.t.sol | 20 +- test/FeesTest.t.sol | 7 +- test/Inbox.t.sol | 2 +- test/SetupTest.t.sol | 14 +- test/apps/Counter.t.sol | 7 +- test/apps/ParallelCounter.t.sol | 8 +- test/apps/SuperToken.t.sol | 7 +- .../counter/CounterAppGateway.sol | 23 +- .../super-token/SuperTokenAppGateway.sol | 2 +- 29 files changed, 374 insertions(+), 312 deletions(-) diff --git a/FunctionSignatures.md b/FunctionSignatures.md index 3eb60034..557f95f5 100644 --- a/FunctionSignatures.md +++ b/FunctionSignatures.md @@ -169,7 +169,7 @@ | `requestOwnershipHandover` | `0x25692962` | | `sbType` | `0x745de344` | | `transferOwnership` | `0xf2fde38b` | -| `transmitterFees` | `0xefb4cdea` | +| `transmitterCredits` | `0xefb4cdea` | | `unblockAndAssignFees` | `0x3c5366a2` | | `unblockFees` | `0xc1867a4b` | | `watcherPrecompileConfig` | `0x8618a912` | diff --git a/contracts/base/AppGatewayBase.sol b/contracts/base/AppGatewayBase.sol index abd4996d..3f252074 100644 --- a/contracts/base/AppGatewayBase.sol +++ b/contracts/base/AppGatewayBase.sol @@ -19,7 +19,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { address public auctionManager; bytes32 public sbType; bytes public onCompleteData; - uint256 public fees; + uint256 public maxFees; mapping(address => bool) public isValidPromise; mapping(bytes32 => mapping(uint32 => address)) public override forwarderAddresses; @@ -36,13 +36,12 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { isAsyncModifierSet = false; // todo: cache the feesApprovalData for next async in same request - deliveryHelper__().batch(fees, auctionManager, feesApprovalData_, onCompleteData); + deliveryHelper__().batch(maxFees, auctionManager, feesApprovalData_, onCompleteData); _markValidPromises(); onCompleteData = bytes(""); } function _preAsync() internal { - if (fees.feePoolChain == 0) revert FeesNotSet(); isAsyncModifierSet = true; _clearOverrides(); deliveryHelper__().clearQueue(); @@ -188,7 +187,8 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { return address(0); } - onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]).getOnChainAddress(); + onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]) + .getOnChainAddress(); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -197,7 +197,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { /// @notice Sets multiple overrides in one call /// @param isReadCall_ The read call flag - /// @param fees_ The fees configuration + /// @param fees_ The maxFees configuration /// @param gasLimit_ The gas limit /// @param isParallelCall_ The sequential call flag function _setOverrides( @@ -209,7 +209,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { overrideParams.isReadCall = isReadCall_; overrideParams.isParallelCall = isParallelCall_; overrideParams.gasLimit = gasLimit_; - fees = fees_; + maxFees = fees_; } function _clearOverrides() internal { @@ -221,7 +221,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { overrideParams.writeFinality = WriteFinality.LOW; } - /// @notice Sets isReadCall, fees and gasLimit overrides + /// @notice Sets isReadCall, maxFees and gasLimit overrides /// @param isReadCall_ The read call flag /// @param isParallelCall_ The sequential call flag /// @param gasLimit_ The gas limit @@ -283,10 +283,10 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { overrideParams.value = value_; } - /// @notice Sets fees overrides - /// @param fees_ The fees configuration - function _setOverrides(uint256 fees_) internal { - fees = fees_; + /// @notice Sets maxFees overrides + /// @param fees_ The maxFees configuration + function _setMaxFees(uint256 fees_) internal { + maxFees = fees_; } function getOverrideParams() @@ -315,7 +315,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { deliveryHelper__().cancelRequest(requestCount_); } - /// @notice increases the transaction fees + /// @notice increases the transaction maxFees /// @param requestCount_ The async ID function _increaseFees(uint40 requestCount_, uint256 newMaxFees_) internal { deliveryHelper__().increaseFees(requestCount_, newMaxFees_); @@ -339,7 +339,7 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway { amount_, receiver_, auctionManager, - fees + maxFees ); } diff --git a/contracts/interfaces/IFeesManager.sol b/contracts/interfaces/IFeesManager.sol index a6c90520..71b0eb70 100644 --- a/contracts/interfaces/IFeesManager.sol +++ b/contracts/interfaces/IFeesManager.sol @@ -5,25 +5,20 @@ import {Bid, QueuePayloadParams} from "../protocol/utils/common/Structs.sol"; interface IFeesManager { function blockFees( - address appGateway_, - uint256 fees_, - Bid memory winningBid_, + address consumeFrom_, + uint256 transmitterCredits_, uint40 requestCount_ ) external; function unblockFees(uint40 requestCount_) external; function isFeesEnough( - address appGateway_, address consumeFrom_, - uint256 fees_ + address appGateway_, + uint256 amount_ ) external view returns (bool); - function unblockAndAssignFees( - uint40 requestCount_, - address transmitter_, - address appGateway_ - ) external; + function unblockAndAssignFees(uint40 requestCount_, address transmitter_) external; function withdrawFees( address appGateway_, @@ -33,10 +28,14 @@ interface IFeesManager { address receiver_ ) external; - function assignWatcherPrecompileFees( - uint32 chainSlug_, - address token_, - uint256 amount_, - address consumeFrom_ + function assignWatcherPrecompileFeesFromRequestCount( + uint256 fees_, + uint40 requestCount_ ) external; + + function assignWatcherPrecompileFeesFromAddress(uint256 fees_, address consumeFrom_) external; + + function setAppGatewayWhitelist( + bytes memory feeApprovalData_ + ) external returns (address consumeFrom, address appGateway, bool isApproved); } diff --git a/contracts/interfaces/IFeesPlug.sol b/contracts/interfaces/IFeesPlug.sol index 1f4357b8..edcd1aef 100644 --- a/contracts/interfaces/IFeesPlug.sol +++ b/contracts/interfaces/IFeesPlug.sol @@ -6,7 +6,11 @@ interface IFeesPlug { function feesRedeemed(bytes32 feesId_) external view returns (bool); - function deposit(address token_, address appGateway_, uint256 amount_) external payable; + function depositToFee(address token_, uint256 amount_, address receiver_) external; + + function depositToFeeAndNative(address token_, uint256 amount_, address receiver_) external; + + function depositToNative(address token_, uint256 amount_, address receiver_) external; function distributeFee( address feeToken_, diff --git a/contracts/interfaces/IMiddleware.sol b/contracts/interfaces/IMiddleware.sol index 46a2410d..d8714e91 100644 --- a/contracts/interfaces/IMiddleware.sol +++ b/contracts/interfaces/IMiddleware.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import {PayloadSubmitParams, QueuePayloadParams, Bid, WriteFinality, CallType, Parallel, IsPlug, RequestMetadata, RequestFee} from "../protocol/utils/common/Structs.sol"; +import {PayloadSubmitParams, QueuePayloadParams, Bid, WriteFinality, CallType, Parallel, IsPlug, RequestMetadata} from "../protocol/utils/common/Structs.sol"; /// @title IMiddleware /// @notice Interface for the Middleware contract diff --git a/contracts/interfaces/IWatcherPrecompile.sol b/contracts/interfaces/IWatcherPrecompile.sol index 0def0da2..54d7d08e 100644 --- a/contracts/interfaces/IWatcherPrecompile.sol +++ b/contracts/interfaces/IWatcherPrecompile.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.21; -import {DigestParams, ResolvedPromises, PayloadParams, TriggerParams, PayloadSubmitParams, RequestParams} from "../protocol/utils/common/Structs.sol"; +import {DigestParams, ResolvedPromises, PayloadParams, TriggerParams, PayloadSubmitParams, Bid, RequestParams, RequestMetadata} from "../protocol/utils/common/Structs.sol"; import {IWatcherPrecompileLimits} from "./IWatcherPrecompileLimits.sol"; import {IWatcherPrecompileConfig} from "./IWatcherPrecompileConfig.sol"; @@ -174,7 +174,8 @@ interface IWatcherPrecompile { function setExpiryTime(uint256 expiryTime_) external; function submitRequest( - PayloadSubmitParams[] calldata payloadSubmitParams + PayloadSubmitParams[] calldata payloadSubmitParams, + RequestMetadata memory requestMetadata ) external returns (uint40 requestCount); function startProcessingRequest(uint40 requestCount, address transmitter) external; diff --git a/contracts/interfaces/IWatcherPrecompileLimits.sol b/contracts/interfaces/IWatcherPrecompileLimits.sol index f7db2adf..394a8cdc 100644 --- a/contracts/interfaces/IWatcherPrecompileLimits.sol +++ b/contracts/interfaces/IWatcherPrecompileLimits.sol @@ -46,14 +46,20 @@ interface IWatcherPrecompileLimits { /// @param appGateway_ The app gateway address /// @param limitType_ The type of limit to consume /// @param consumeLimit_ The amount of limit to consume - function consumeLimit(address appGateway_, bytes32 limitType_, uint256 consumeLimit_) external; + function consumeLimit( + uint40 requestCount_, + address appGateway_, + bytes32 limitType_, + uint256 consumeLimit_ + ) external; + + function getTotalFeesRequired(uint40 requestCount_) external view returns (uint256); + + function queryFees() external view returns (uint256); + function finalizeFees() external view returns (uint256); + function scheduleFees() external view returns (uint256); + function callBackFees() external view returns (uint256); - function getTotalFeesRequired( - address token_, - uint queryCount, - uint finalizeCount, - uint scheduleCount - ) external view returns (uint256); /// @notice Emitted when limit parameters are updated event LimitParamsUpdated(UpdateLimitParams[] updates); diff --git a/contracts/protocol/payload-delivery/AuctionManager.sol b/contracts/protocol/payload-delivery/AuctionManager.sol index a27cbd3f..632a3d15 100644 --- a/contracts/protocol/payload-delivery/AuctionManager.sol +++ b/contracts/protocol/payload-delivery/AuctionManager.sol @@ -95,38 +95,38 @@ contract AuctionManager is /// @notice Places a bid for an auction /// @param requestCount_ The ID of the auction - /// @param fee The bid amount + /// @param bidFees The bid amount /// @param transmitterSignature The signature of the transmitter function bid( uint40 requestCount_, - uint256 fee, + uint256 bidFees, bytes memory transmitterSignature, bytes memory extraData ) external { if (auctionClosed[requestCount_]) revert AuctionClosed(); + RequestMetadata memory requestMetadata = _getRequestMetadata(requestCount_); // check if the transmitter is valid address transmitter = _recoverSigner( - keccak256(abi.encode(address(this), evmxSlug, requestCount_, fee, extraData)), + keccak256(abi.encode(address(this), evmxSlug, requestCount_, bidFees, extraData)), transmitterSignature ); if (!_hasRole(TRANSMITTER_ROLE, transmitter)) revert InvalidTransmitter(); - (uint256 watcherFees, uint256 transmitterFees) = getTransmitterMaxFeesRequired( - requestMetadata.fees.token, + (uint256 watcherFees, uint256 transmitterCredits) = getTransmitterMaxFeesRequired( requestCount_ + // check if the bid exceeds the max fees quoted by app gateway subtracting the watcher fees ); - // check if the bid exceeds the max fees quoted by app gateway subtracting the watcher fees - if (fee > transmitterFees) revert BidExceedsMaxFees(); + if (bidFees > transmitterCredits) revert BidExceedsMaxFees(); // check if the bid is lower than the existing bid if ( winningBids[requestCount_].transmitter != address(0) && - fee >= winningBids[requestCount_].fee + bidFees >= winningBids[requestCount_].fee ) revert LowerBidAlreadyExists(); // create a new bid - Bid memory newBid = Bid({fee: fee, transmitter: transmitter, extraData: extraData}); + Bid memory newBid = Bid({fee: bidFees, transmitter: transmitter, extraData: extraData}); // update the winning bid winningBids[requestCount_] = newBid; @@ -158,7 +158,7 @@ contract AuctionManager is if (winningBid.transmitter == address(0)) revert InvalidTransmitter(); auctionClosed[requestCount_] = true; - + RequestMetadata memory requestMetadata = _getRequestMetadata(requestCount_); // block the fees IFeesManager(addressResolver__.feesManager()).blockFees( requestMetadata.consumeFrom, @@ -209,19 +209,18 @@ contract AuctionManager is } function getTransmitterMaxFeesRequired( - address token_, uint40 requestCount_ ) public view returns (uint256, uint256) { + RequestMetadata memory requestMetadata = _getRequestMetadata(requestCount_); + // check if the bid is for this auction manager if (requestMetadata.auctionManager != address(this)) revert InvalidBid(); // get the request metadata - RequestMetadata memory requestMetadata = IMiddleware(addressResolver__.deliveryHelper()) - .getRequestMetadata(requestCount_); // get the total fees required for the watcher precompile ops - uint256 watcherFees = watcherPrecompile__().getTotalFeesRequired(token_, requestCount_); - return (watcherFees, requestMetadata.fees.amount - watcherFees); + uint256 watcherFees = watcherPrecompileLimits().getTotalFeesRequired(requestCount_); + return (watcherFees, requestMetadata.maxFees - watcherFees); } function _recoverSigner( @@ -232,4 +231,10 @@ contract AuctionManager is // recovered signer is checked for the valid roles later signer = ECDSA.recover(digest, signature_); } + + function _getRequestMetadata( + uint40 requestCount_ + ) internal view returns (RequestMetadata memory) { + return IMiddleware(addressResolver__.deliveryHelper()).getRequestMetadata(requestCount_); + } } diff --git a/contracts/protocol/payload-delivery/FeesManager.sol b/contracts/protocol/payload-delivery/FeesManager.sol index 0e1bc855..260c4b52 100644 --- a/contracts/protocol/payload-delivery/FeesManager.sol +++ b/contracts/protocol/payload-delivery/FeesManager.sol @@ -10,7 +10,7 @@ import {IFeesManager} from "../../interfaces/IFeesManager.sol"; import {AddressResolverUtil} from "../utils/AddressResolverUtil.sol"; import {NotAuctionManager, InvalidWatcherSignature, NonceUsed} from "../utils/common/Errors.sol"; -import {Bid, CallType, Parallel, WriteFinality, QueuePayloadParams, IsPlug, PayloadSubmitParams, RequestMetadata, RequestFee, UserCredits} from "../utils/common/Structs.sol"; +import {Bid, CallType, Parallel, WriteFinality, QueuePayloadParams, IsPlug, PayloadSubmitParams, RequestMetadata, UserCredits} from "../utils/common/Structs.sol"; abstract contract FeesManagerStorage is IFeesManager { // slots [0-49] reserved for gap @@ -28,6 +28,9 @@ abstract contract FeesManagerStorage is IFeesManager { // user credits mapping(address => UserCredits) public userCredits; + // user nonce + mapping(address => uint256) public userNonce; + // token pool balances // token address => chainSlug => amount mapping(address => mapping(uint32 => uint256)) public tokenPoolBalances; @@ -39,7 +42,7 @@ abstract contract FeesManagerStorage is IFeesManager { // slot 54 /// @notice Mapping to track request credits details for each request count /// @dev requestCount => RequestFee - mapping(uint40 => RequestFee) public requestCountCredits; + mapping(uint40 => uint256) public requestCountCredits; // slot 55 /// @notice Mapping to track credits to be distributed to transmitters @@ -65,15 +68,9 @@ abstract contract FeesManagerStorage is IFeesManager { contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResolverUtil { /// @notice Emitted when fees are blocked for a batch /// @param requestCount The batch identifier - /// @param chainSlug The chain identifier - /// @param token The token address + /// @param consumeFrom The consume from address /// @param amount The blocked amount - event FeesBlocked( - uint40 indexed requestCount, - uint32 indexed chainSlug, - address indexed token, - uint256 amount - ); + event FeesBlocked(uint40 indexed requestCount, address indexed consumeFrom, uint256 amount); /// @notice Emitted when transmitter fees are updated /// @param requestCount The batch identifier @@ -84,12 +81,7 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol address indexed transmitter, uint256 amount ); - event WatcherPrecompileFeesAssigned( - uint32 chainSlug, - address token, - uint256 amount, - address consumeFrom - ); + event WatcherPrecompileFeesAssigned(uint256 amount, address consumeFrom); /// @notice Emitted when fees deposited are updated /// @param chainSlug The chain identifier /// @param appGateway The app gateway address @@ -163,33 +155,72 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol } /// @notice Adds the fees deposited for an app gateway on a chain - /// @param consumeFrom_ The app gateway address + /// @param depositTo_ The app gateway address /// @param amount_ The amount deposited + // @dev only callable by watcher precompile + // @dev will need tokenAmount_ and creditAmount_ when introduce tokens except stables function incrementFeesDeposited( - address consumeFrom_, + address depositTo_, + uint32 chainSlug_, + address token_, uint256 amount_, uint256 signatureNonce_, bytes memory signature_ ) external { - _isWatcherSignatureValid(abi.encode(consumeFrom_, amount_), signatureNonce_, signature_); + _isWatcherSignatureValid( + abi.encode(depositTo_, chainSlug_, token_, amount_), + signatureNonce_, + signature_ + ); - UserCredits storage userCredit = userCredits[consumeFrom_]; + UserCredits storage userCredit = userCredits[depositTo_]; userCredit.totalCredits += amount_; tokenPoolBalances[token_][chainSlug_] += amount_; - emit FeesDepositedUpdated(consumeFrom_, amount_); + emit FeesDepositedUpdated(chainSlug_, depositTo_, token_, amount_); } function isFeesEnough( - address appGateway_, address consumeFrom_, + address appGateway_, uint256 amount_ ) external view returns (bool) { - address appGateway = _getCoreAppGateway(consumeFrom_); - if (!isAppGatewayWhitelisted[consumeFrom_][appGateway]) return false; + if (!isAppGatewayWhitelisted[consumeFrom_][appGateway_]) return false; return getAvailableFees(consumeFrom_) >= amount_; } + function _processFeeApprovalData( + bytes memory feeApprovalData_ + ) internal view returns (address consumeFrom, address appGateway, bool isApproved) { + bytes memory signature_; + (consumeFrom, appGateway, isApproved, signature_) = abi.decode( + feeApprovalData_, + (address, address, bool, bytes) + ); + if (signature_.length == 0) return (consumeFrom, appGateway, isApproved); + bytes32 digest = keccak256( + abi.encode( + address(this), + evmxSlug, + consumeFrom, + appGateway, + userNonce[consumeFrom], + isApproved + ) + ); + if (ECDSA.recover(digest, signature_) != consumeFrom) revert InvalidWatcherSignature(); + + isAppGatewayWhitelisted[consumeFrom][appGateway] = isApproved; + userNonce[consumeFrom]++; + return (consumeFrom, appGateway, isApproved); + } + + function setAppGatewayWhitelist( + bytes memory feeApprovalData_ + ) external returns (address consumeFrom, address appGateway, bool isApproved) { + return _processFeeApprovalData(feeApprovalData_); + } + /// @notice Whitelists multiple app gateways for the caller /// @param appGateways_ Array of app gateway addresses to whitelist function whitelistApps(address[] calldata appGateways_) external { @@ -197,32 +228,31 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol isAppGatewayWhitelisted[msg.sender][appGateways_[i]] = true; } } - + modifier onlyAuctionManager(uint40 requestCount_) { + if (msg.sender != deliveryHelper__().getRequestMetadata(requestCount_).auctionManager) + revert NotAuctionManager(); + _; + } /// @notice Blocks fees for a request count /// @param consumeFrom_ The fees payer address - /// @param transmitterFees_ The total fees to block + /// @param transmitterCredits_ The total fees to block /// @param requestCount_ The batch identifier /// @dev Only callable by delivery helper function blockFees( address consumeFrom_, - uint256 transmitterFees_, + uint256 transmitterCredits_, uint40 requestCount_ - ) external { - if (msg.sender != deliveryHelper__().getRequestMetadata(requestCount_).auctionManager) - revert NotAuctionManager(); - + ) external onlyAuctionManager(requestCount_) { // Block fees - if (getAvailableFees(consumeFrom_) < transmitterFees_) revert InsufficientFeesAvailable(); + if (getAvailableFees(consumeFrom_) < transmitterCredits_) + revert InsufficientFeesAvailable(); UserCredits storage userCredit = userCredits[consumeFrom_]; - userCredit.blockedCredits += transmitterFees_; + userCredit.blockedCredits += transmitterCredits_; - requestCountCredits[requestCount_] = RequestFee({ - blockedCredits: transmitterFees_, - consumeFrom: consumeFrom_ - }); + requestCountCredits[requestCount_] = transmitterCredits_; - emit FeesBlocked(requestCount_, transmitterFees_); + emit FeesBlocked(requestCount_, consumeFrom_, transmitterCredits_); } /// @notice Unblocks fees after successful execution and assigns them to the transmitter @@ -232,16 +262,18 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol uint40 requestCount_, address transmitter_ ) external override onlyDeliveryHelper { - RequestFee memory requestFee = requestCountCredits[requestCount_]; - if (requestFee.blockedCredits == 0) return; - - uint256 fees = deliveryHelper__().getRequestMetadata(requestCount_).winningBid.fee; + uint256 blockedCredits = requestCountCredits[requestCount_]; + if (blockedCredits == 0) return; + RequestMetadata memory requestMetadata = deliveryHelper__().getRequestMetadata( + requestCount_ + ); + uint256 fees = requestMetadata.winningBid.fee; // Unblock fees from deposit - _useBlockedUserCredits(requestFee.consumeFrom, fees, fees); + _useBlockedUserCredits(requestMetadata.consumeFrom, blockedCredits, fees); // Assign fees to transmitter - transmitterFees[transmitter_] += fees; + transmitterCredits[transmitter_] += fees; // Clean up storage delete requestCountCredits[requestCount_]; @@ -250,27 +282,43 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol function _useBlockedUserCredits( address consumeFrom_, - uint256 toBlock_, - uint256 toConsume_ + uint256 toConsumeFromBlocked_, + uint256 toConsumeFromTotal_ ) internal { UserCredits storage userCredit = userCredits[consumeFrom_]; - userCredit.blockedCredits -= toBlock_; + userCredit.blockedCredits -= toConsumeFromBlocked_; + userCredit.totalCredits -= toConsumeFromTotal_; + } + + function _useAvailableUserCredits(address consumeFrom_, uint256 toConsume_) internal { + UserCredits storage userCredit = userCredits[consumeFrom_]; userCredit.totalCredits -= toConsume_; } - function assignWatcherPrecompileFees( - uint256 amount_, + function assignWatcherPrecompileFeesFromRequestCount( + uint256 fees_, uint40 requestCount_ ) external onlyWatcherPrecompile { - RequestFee memory requestFee = requestCountCredits[requestCount_]; - if (requestFee.blockedCredits == 0) revert NoFeesBlocked(); + require(requestCount_ != 0, "Request count cannot be 0"); + RequestMetadata memory requestMetadata = deliveryHelper__().getRequestMetadata( + requestCount_ + ); + _assignWatcherPrecompileFees(fees_, requestMetadata.consumeFrom); + } - // deduct the fees from the user - _useBlockedUserCredits(requestFee.consumeFrom, 0, amount_); + function assignWatcherPrecompileFeesFromAddress( + uint256 fees_, + address consumeFrom_ + ) external onlyWatcherPrecompile { + _assignWatcherPrecompileFees(fees_, consumeFrom_); + } + function _assignWatcherPrecompileFees(uint256 fees_, address consumeFrom_) internal { + // deduct the fees from the user + _useAvailableUserCredits(consumeFrom_, fees_); // add the fees to the watcher precompile - watcherPrecompileCredits += amount_; - emit WatcherPrecompileFeesAssigned(requestCount_, amount_); + watcherPrecompileCredits += fees_; + emit WatcherPrecompileFeesAssigned(fees_, consumeFrom_); } function unblockFees(uint40 requestCount_) external { @@ -283,45 +331,15 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol msg.sender != address(deliveryHelper__()) ) revert InvalidCaller(); - RequestFee memory requestFee = requestCountCredits[requestCount_]; - if (requestFee.blockedCredits == 0) return; + uint256 blockedCredits = requestCountCredits[requestCount_]; + if (blockedCredits == 0) return; // Unblock fees from deposit - UserCredits storage userCredit = userCredits[requestFee.consumeFrom]; - userCredit.blockedCredits -= requestFee.blockedCredits; + UserCredits storage userCredit = userCredits[requestMetadata.consumeFrom]; + userCredit.blockedCredits -= blockedCredits; delete requestCountCredits[requestCount_]; - emit FeesUnblocked(requestCount_, requestFee.consumeFrom); - } - - /// @notice Withdraws fees to a specified receiver - /// @param chainSlug_ The chain identifier - /// @param token_ The token address - /// @param receiver_ The address of the receiver - function withdrawTransmitterFees( - uint32 chainSlug_, - address token_, - address receiver_, - uint256 amount_ - ) external returns (uint40 requestCount) { - address transmitter = msg.sender; - // Get total fees for the transmitter in given chain and token - uint256 totalFees = transmitterFees[transmitter]; - if (totalFees >= amount_) revert InsufficientFeesAvailable(); - - // Clean up storage - transmitterFees[transmitter] -= amount_; - tokenPoolBalances[token_][chainSlug_] -= amount_; - - // Create fee distribution payload - bytes32 feesId = _encodeFeesId(feesCounter++); - bytes memory payload = abi.encodeCall( - IFeesPlug.distributeFee, - (token_, amount_, receiver_, feesId) - ); - - // finalize for plug contract - return _submitAndStartProcessing(chainSlug_, payload, transmitter); + emit FeesUnblocked(requestCount_, requestMetadata.consumeFrom); } /// @notice Withdraws funds to a specified receiver @@ -351,11 +369,31 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol _queue(chainSlug_, abi.encodeCall(IFeesPlug.withdrawFees, (token_, amount_, receiver_))); } - function _submitAndStartProcessing( + /// @notice Withdraws fees to a specified receiver + /// @param chainSlug_ The chain identifier + /// @param token_ The token address + /// @param receiver_ The address of the receiver + function withdrawTransmitterFees( uint32 chainSlug_, - bytes memory payload_, - address transmitter_ - ) internal returns (uint40 requestCount) { + address token_, + address receiver_, + uint256 amount_ + ) external returns (uint40 requestCount) { + address transmitter = msg.sender; + // Get total fees for the transmitter in given chain and token + uint256 totalFees = transmitterCredits[transmitter]; + if (totalFees >= amount_) revert InsufficientFeesAvailable(); + + // Clean up storage + transmitterCredits[transmitter] -= amount_; + tokenPoolBalances[token_][chainSlug_] -= amount_; + + // Create fee distribution payload + bytes32 feesId = _encodeFeesId(feesCounter++); + bytes memory payload = abi.encodeCall( + IFeesPlug.distributeFee, + (token_, amount_, receiver_, feesId) + ); PayloadSubmitParams[] memory payloadSubmitParamsArray = new PayloadSubmitParams[](1); payloadSubmitParamsArray[0] = PayloadSubmitParams({ levelNumber: 0, @@ -370,20 +408,29 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol gasLimit: 10000000, value: 0, readAt: 0, - payload: payload_ + payload: payload }); RequestMetadata memory requestMetadata = RequestMetadata({ appGateway: address(this), auctionManager: address(0), - feesApprovalData: bytes(""), - fees: amount_, - winningBid: Bid({transmitter: transmitter_, fee: 0, extraData: new bytes(0)}) - }); + maxFees: 0, + winningBid: Bid({transmitter: transmitter, fee: 0, extraData: new bytes(0)}), + onCompleteData: bytes(""), + onlyReadRequests: false, + consumeFrom: address(0) + }); // finalize for plug contract + return _submitAndStartProcessing(payloadSubmitParamsArray, requestMetadata, transmitter); + } + function _submitAndStartProcessing( + PayloadSubmitParams[] memory payloadSubmitParamsArray_, + RequestMetadata memory requestMetadata_, + address transmitter_ + ) internal returns (uint40 requestCount) { requestCount = watcherPrecompile__().submitRequest( - payloadSubmitParamsArray, - requestMetadata + payloadSubmitParamsArray_, + requestMetadata_ ); // same transmitter can execute requests without auction diff --git a/contracts/protocol/payload-delivery/FeesPlug.sol b/contracts/protocol/payload-delivery/FeesPlug.sol index 2f5bc16f..ab6784ce 100644 --- a/contracts/protocol/payload-delivery/FeesPlug.sol +++ b/contracts/protocol/payload-delivery/FeesPlug.sol @@ -113,7 +113,7 @@ contract FeesPlug is IFeesPlug, PlugBase, AccessControl { address receiver_, uint256 feeAmount_, uint256 nativeAmount_ - ) internal override { + ) internal { uint256 totalAmount_ = feeAmount_ + nativeAmount_; if (!whitelistedTokens[token_]) revert TokenNotWhitelisted(token_); if (token_.code.length == 0) revert InvalidTokenAddress(); diff --git a/contracts/protocol/payload-delivery/app-gateway/DeliveryHelper.sol b/contracts/protocol/payload-delivery/app-gateway/DeliveryHelper.sol index 6c7b0c80..6efaedfd 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_); + watcherPrecompile__().startProcessingRequest(requestCount_, winningBid_.transmitter); } else { watcherPrecompile__().updateTransmitter(requestCount_, winningBid_.transmitter); } @@ -56,8 +56,7 @@ contract DeliveryHelper is FeesHelpers { if (requestMetadata_.winningBid.transmitter != address(0)) IFeesManager(addressResolver__.feesManager()).unblockAndAssignFees( requestCount_, - requestMetadata_.winningBid.transmitter, - requestMetadata_.appGateway + requestMetadata_.winningBid.transmitter ); IAppGateway(requestMetadata_.appGateway).onRequestComplete( @@ -95,8 +94,7 @@ contract DeliveryHelper is FeesHelpers { if (requests[requestCount_].winningBid.transmitter != address(0)) { IFeesManager(addressResolver__.feesManager()).unblockAndAssignFees( requestCount_, - requests[requestCount_].winningBid.transmitter, - requests[requestCount_].appGateway + requests[requestCount_].winningBid.transmitter ); } else { // If the request has no winning bid, ie. transmitter not assigned, unblock fees diff --git a/contracts/protocol/payload-delivery/app-gateway/FeesHelpers.sol b/contracts/protocol/payload-delivery/app-gateway/FeesHelpers.sol index ccda6afe..2922ba52 100644 --- a/contracts/protocol/payload-delivery/app-gateway/FeesHelpers.sol +++ b/contracts/protocol/payload-delivery/app-gateway/FeesHelpers.sol @@ -21,7 +21,7 @@ abstract contract FeesHelpers is RequestQueue { } if (requests[requestCount_].winningBid.transmitter != address(0)) revert WinningBidExists(); - requests[requestCount_].fees.amount = newMaxFees_; + requests[requestCount_].maxFees = newMaxFees_; emit FeesIncreased(appGateway, requestCount_, newMaxFees_); } @@ -47,13 +47,13 @@ abstract contract FeesHelpers is RequestQueue { receiver_ ); - return _batch(msg.sender, auctionManager_, fees_, bytes("")); + return _batch(msg.sender, auctionManager_, fees_, bytes(""), bytes("")); } /// @notice Returns the fees for a request /// @param requestCount_ The ID of the request /// @return fees The fees data function getFees(uint40 requestCount_) external view returns (uint256) { - return requests[requestCount_].fees.amount; + return requests[requestCount_].maxFees; } } diff --git a/contracts/protocol/payload-delivery/app-gateway/RequestQueue.sol b/contracts/protocol/payload-delivery/app-gateway/RequestQueue.sol index 12d9d458..dac1a41d 100644 --- a/contracts/protocol/payload-delivery/app-gateway/RequestQueue.sol +++ b/contracts/protocol/payload-delivery/app-gateway/RequestQueue.sol @@ -20,34 +20,38 @@ abstract contract RequestQueue is DeliveryUtils { } /// @notice Initiates a batch of payloads - /// @param fees_ The fees data + /// @param maxFees_ The fees data /// @param auctionManager_ The auction manager address /// @return requestCount The ID of the batch function batch( - uint256 fees_, + uint256 maxFees_, address auctionManager_, bytes memory feesApprovalData_, bytes memory onCompleteData_ ) external returns (uint40 requestCount) { address appGateway = _getCoreAppGateway(msg.sender); - return _batch(appGateway, auctionManager_, fees_, feesApprovalData_, onCompleteData_); + return _batch(appGateway, auctionManager_, maxFees_, feesApprovalData_, onCompleteData_); } function _checkBatch( address appGateway_, bytes memory feesApprovalData_, - uint256 fees_ - ) internal view { + uint256 maxFees_ + ) internal view returns (address consumeFrom) { if (queuePayloadParams.length > REQUEST_PAYLOAD_COUNT_LIMIT) revert RequestPayloadCountLimitExceeded(); - + (consumeFrom, , ) = IFeesManager(addressResolver__.feesManager()).setAppGatewayWhitelist( + feesApprovalData_ + ); if ( !IFeesManager(addressResolver__.feesManager()).isFeesEnough( + consumeFrom, appGateway_, - feesApprovalData_, - fees_ + maxFees_ ) ) revert InsufficientFees(); + + return consumeFrom; } function _getAuctionManager(address auctionManager_) internal view returns (address) { @@ -64,7 +68,7 @@ abstract contract RequestQueue is DeliveryUtils { function _batch( address appGateway_, address auctionManager_, - uint256 fees_, + uint256 maxFees_, bytes memory feesApprovalData_, bytes memory onCompleteData_ ) internal returns (uint40 requestCount) { @@ -77,15 +81,15 @@ abstract contract RequestQueue is DeliveryUtils { bool onlyReadRequests ) = _createPayloadSubmitParamsArray(); - _checkBatch(appGateway_, feesApprovalData_, fees_); + address consumeFrom = _checkBatch(appGateway_, feesApprovalData_, maxFees_); RequestMetadata memory requestMetadata = RequestMetadata({ appGateway: appGateway_, auctionManager: auctionManager, - feesApprovalData: feesApprovalData_, - fees: fees_, + maxFees: maxFees_, winningBid: Bid({fee: 0, transmitter: address(0), extraData: new bytes(0)}), onCompleteData: onCompleteData_, - onlyReadRequests: onlyReadRequests + onlyReadRequests: onlyReadRequests, + consumeFrom: consumeFrom }); // process and submit the queue of payloads to watcher precompile @@ -101,14 +105,14 @@ abstract contract RequestQueue is DeliveryUtils { watcherPrecompile__().startProcessingRequest(requestCount, address(0)); // to save extra calls from transmitter - uint256 maxTransmitterFees = fees_ - - watcherPrecompile__().getTotalFeesRequired(requestCount); + uint256 maxTransmitterFees = maxFees_ - + watcherPrecompileLimits().getTotalFeesRequired(requestCount); emit PayloadSubmitted( requestCount, appGateway_, payloadSubmitParamsArray, - fees_ - maxTransmitterFees, + maxFees_ - maxTransmitterFees, auctionManager_, onlyReadRequests ); diff --git a/contracts/protocol/utils/AddressResolverUtil.sol b/contracts/protocol/utils/AddressResolverUtil.sol index ec6ba238..21f24611 100644 --- a/contracts/protocol/utils/AddressResolverUtil.sol +++ b/contracts/protocol/utils/AddressResolverUtil.sol @@ -6,6 +6,7 @@ import "../../interfaces/IMiddleware.sol"; import "../../interfaces/IWatcherPrecompile.sol"; import "../../interfaces/IWatcherPrecompileConfig.sol"; import "../../interfaces/IWatcherPrecompileLimits.sol"; +import "../../interfaces/IFeesManager.sol"; /// @title AddressResolverUtil /// @notice Utility contract for resolving system contract addresses diff --git a/contracts/protocol/utils/common/Constants.sol b/contracts/protocol/utils/common/Constants.sol index bf6c8d4a..7b17f483 100644 --- a/contracts/protocol/utils/common/Constants.sol +++ b/contracts/protocol/utils/common/Constants.sol @@ -9,6 +9,7 @@ bytes32 constant DEPLOY = keccak256("DEPLOY"); bytes32 constant QUERY = keccak256("QUERY"); bytes32 constant FINALIZE = keccak256("FINALIZE"); bytes32 constant SCHEDULE = keccak256("SCHEDULE"); +bytes32 constant CALLBACK = keccak256("CALLBACK"); bytes32 constant FAST = keccak256("FAST"); uint256 constant REQUEST_PAYLOAD_COUNT_LIMIT = 10; uint256 constant PAYLOAD_SIZE_LIMIT = 24_500; diff --git a/contracts/protocol/utils/common/Structs.sol b/contracts/protocol/utils/common/Structs.sol index 36c73bb0..4dcffff9 100644 --- a/contracts/protocol/utils/common/Structs.sol +++ b/contracts/protocol/utils/common/Structs.sol @@ -108,6 +108,12 @@ struct Bid { bytes extraData; } +struct OnChainFees { + uint32 chainSlug; + address token; + uint256 amount; +} + // App gateway base: struct OverrideParams { Read isReadCall; @@ -118,12 +124,6 @@ struct OverrideParams { uint256 readAt; } -// FM: -struct RequestFee { - uint256 blockedCredits; - address consumeFrom; -} - struct UserCredits { uint256 totalCredits; uint256 blockedCredits; @@ -219,11 +219,11 @@ struct RequestParams { struct RequestMetadata { address appGateway; address auctionManager; - uint256 fees; + uint256 maxFees; Bid winningBid; bytes onCompleteData; bool onlyReadRequests; - bytes feesApprovalData; + address consumeFrom; } struct ExecuteParams { diff --git a/contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol b/contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol index 0ab07deb..89e99779 100644 --- a/contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol +++ b/contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol @@ -6,7 +6,7 @@ import {Ownable} from "solady/auth/Ownable.sol"; import {Gauge} from "../utils/Gauge.sol"; import {AddressResolverUtil} from "../utils/AddressResolverUtil.sol"; import "../../interfaces/IWatcherPrecompileLimits.sol"; -import {SCHEDULE, QUERY, FINALIZE} from "../utils/common/Constants.sol"; +import {SCHEDULE, QUERY, FINALIZE, CALLBACK} from "../utils/common/Constants.sol"; /// @title WatcherPrecompileLimits /// @notice Contract for managing watcher precompile limits @@ -43,16 +43,20 @@ contract WatcherPrecompileLimits is // Mapping to track active app gateways mapping(address => bool) internal _activeAppGateways; - // token => fee amount - mapping(address => uint256) public queryFees; - mapping(address => uint256) public finalizeFees; - mapping(address => uint256) public scheduleFees; - mapping(address => uint256) public callBackFees; + // slot 156: precompileCount + // limitType => requestCount => count + mapping(bytes32 => mapping(uint40 => uint256)) public precompileCount; + + // slot 157: fees + uint256 public queryFees; + uint256 public finalizeFees; + uint256 public scheduleFees; + uint256 public callBackFees; /// @notice Emitted when the default limit and rate per second are set event DefaultLimitAndRatePerSecondSet(uint256 defaultLimit, uint256 defaultRatePerSecond); - event WatcherFeesNotSetForToken(address token_); + error WatcherFeesNotSet(bytes32 limitType); /// @notice Initial initialization (version 1) function initialize( address owner_, @@ -167,63 +171,45 @@ contract WatcherPrecompileLimits is emit DefaultLimitAndRatePerSecondSet(defaultLimit, defaultRatePerSecond); } - function setQueryFees( - address[] calldata tokens_, - uint256[] calldata amounts_ - ) external onlyOwner { - require(tokens_.length == amounts_.length, "Length mismatch"); - for (uint256 i = 0; i < tokens_.length; i++) { - queryFees[tokens_[i]] = amounts_[i]; - } + function setQueryFees(uint256 queryFees_) external onlyOwner { + queryFees = queryFees_; } - function setFinalizeFees( - address[] calldata tokens_, - uint256[] calldata amounts_ - ) external onlyOwner { - require(tokens_.length == amounts_.length, "Length mismatch"); - for (uint256 i = 0; i < tokens_.length; i++) { - finalizeFees[tokens_[i]] = amounts_[i]; - } + function setFinalizeFees(uint256 finalizeFees_) external onlyOwner { + finalizeFees = finalizeFees_; } - function setScheduleFees( - address[] calldata tokens_, - uint256[] calldata amounts_ - ) external onlyOwner { - require(tokens_.length == amounts_.length, "Length mismatch"); - for (uint256 i = 0; i < tokens_.length; i++) { - scheduleFees[tokens_[i]] = amounts_[i]; - } + function setScheduleFees(uint256 scheduleFees_) external onlyOwner { + scheduleFees = scheduleFees_; } - 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 setCallBackFees(uint256 callBackFees_) external onlyOwner { + callBackFees = callBackFees_; } - function getTotalFeesRequired( - address token_, - uint40 requestCount_ - ) external view returns (uint256) { + function getTotalFeesRequired(uint40 requestCount_) external view returns (uint256) { uint256 totalFees = 0; - if (queryFees[token_] == 0 || finalizeFees[token_] == 0 || scheduleFees[token_] == 0) { - revert WatcherFeesNotSetForToken(token_); + if (queryFees == 0) { + revert WatcherFeesNotSet(QUERY); + } + if (finalizeFees == 0) { + revert WatcherFeesNotSet(FINALIZE); + } + if (scheduleFees == 0) { + revert WatcherFeesNotSet(SCHEDULE); + } + if (callBackFees == 0) { + revert WatcherFeesNotSet(CALLBACK); } 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_]; + totalFees += totalCallbacks * callBackFees; + totalFees += precompileCount[QUERY][requestCount_] * queryFees; + totalFees += precompileCount[FINALIZE][requestCount_] * finalizeFees; + totalFees += precompileCount[SCHEDULE][requestCount_] * scheduleFees; return totalFees; } diff --git a/contracts/protocol/watcherPrecompile/core/RequestHandler.sol b/contracts/protocol/watcherPrecompile/core/RequestHandler.sol index 3d00e32d..f89e36e5 100644 --- a/contracts/protocol/watcherPrecompile/core/RequestHandler.sol +++ b/contracts/protocol/watcherPrecompile/core/RequestHandler.sol @@ -14,15 +14,16 @@ abstract contract RequestHandler is WatcherPrecompileCore { uint256[50] _request_handler_gap; /// @notice Submits a batch of payload requests from middleware - /// @param payloadSubmitParams Array of payload submit parameters + /// @param payloadSubmitParams_ Array of payload submit parameters + /// @param requestMetadata_ Request metadata /// @return requestCount The unique identifier for the submitted request /// @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, - RequestMetadata calldata requestMetadata + PayloadSubmitParams[] calldata payloadSubmitParams_, + RequestMetadata calldata requestMetadata_ ) public returns (uint40 requestCount) { - address appGateway = _checkAppGateways(payloadSubmitParams); + address appGateway = _checkAppGateways(payloadSubmitParams_); requestCount = nextRequestCount++; uint40 batchCount = nextBatchCount; @@ -32,8 +33,8 @@ abstract contract RequestHandler is WatcherPrecompileCore { uint256 writeCount; PayloadSubmitParams memory lastP; - for (uint256 i = 0; i < payloadSubmitParams.length; i++) { - PayloadSubmitParams memory p = payloadSubmitParams[i]; + for (uint256 i = 0; i < payloadSubmitParams_.length; i++) { + PayloadSubmitParams memory p = payloadSubmitParams_[i]; // Count reads and writes for checking limits if (p.callType == CallType.READ) { @@ -94,11 +95,9 @@ abstract contract RequestHandler is WatcherPrecompileCore { watcherPrecompileLimits__.consumeLimit(appGateway, FINALIZE, writeCount); requestParams[requestCount].currentBatch = currentBatch; - requestParams[requestCount].payloadsRemaining = payloadSubmitParams.length; + requestParams[requestCount].payloadsRemaining = payloadSubmitParams_.length; requestParams[requestCount].middleware = msg.sender; - requestMetadata[requestCount] = requestMetadata; - emit RequestSubmitted( msg.sender, requestCount, @@ -132,17 +131,17 @@ abstract contract RequestHandler is WatcherPrecompileCore { /// @notice Starts processing a request with a specified transmitter /// @param requestCount The request count to start processing - /// @param winningBid The winning bid, contains fees, transmitter and extra data + /// @param transmitter_ 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, Bid memory winningBid) public { + function startProcessingRequest(uint40 requestCount, address transmitter_) 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 = winningBid.transmitter; + r.transmitter = transmitter_; r.currentBatch = batchCount; _processBatch(requestCount, batchCount); diff --git a/contracts/protocol/watcherPrecompile/core/WatcherPrecompile.sol b/contracts/protocol/watcherPrecompile/core/WatcherPrecompile.sol index 40f1b13d..bcea7bd0 100644 --- a/contracts/protocol/watcherPrecompile/core/WatcherPrecompile.sol +++ b/contracts/protocol/watcherPrecompile/core/WatcherPrecompile.sol @@ -312,11 +312,8 @@ contract WatcherPrecompile is RequestHandler { ) ) revert InvalidCallerTriggered(); - IFeesManager(addressResolver__.feesManager()).assignWatcherPrecompileFees( - address(0), - uint32(0), - watcherPrecompileLimits__().callBackFees(params_[i].payload), - uint40(0), + IFeesManager(addressResolver__.feesManager()).assignWatcherPrecompileFeesFromAddress( + watcherPrecompileLimits__.callBackFees(), appGateway ); diff --git a/contracts/protocol/watcherPrecompile/core/WatcherPrecompileCore.sol b/contracts/protocol/watcherPrecompile/core/WatcherPrecompileCore.sol index d8cef4f0..da6c919d 100644 --- a/contracts/protocol/watcherPrecompile/core/WatcherPrecompileCore.sol +++ b/contracts/protocol/watcherPrecompile/core/WatcherPrecompileCore.sol @@ -6,7 +6,7 @@ import {ECDSA} from "solady/utils/ECDSA.sol"; import {AccessControl} from "../../utils/AccessControl.sol"; import "solady/utils/Initializable.sol"; import {AddressResolverUtil} from "../../utils/AddressResolverUtil.sol"; - +import {IFeesManager} from "../../../interfaces/IFeesManager.sol"; /// @title WatcherPrecompileCore /// @notice Core functionality for the WatcherPrecompile system /// @dev This contract implements the core functionality for payload verification, execution, and app configurations @@ -33,10 +33,7 @@ abstract contract WatcherPrecompileCore is ) internal returns (bytes32 timeoutId) { if (delayInSeconds_ > maxTimeoutDelayInSeconds) revert TimeoutDelayTooLarge(); - _consumeFees( - requestCount_, - watcherPrecompileLimits__.scheduleFees(requestMetadata_.fees.feePoolToken) - ); + _consumeCallbackFeesFromAddress(watcherPrecompileLimits__.scheduleFees(), msg.sender); uint256 executeAt = block.timestamp + delayInSeconds_; timeoutId = _encodeTimeoutId(); @@ -79,9 +76,9 @@ abstract contract WatcherPrecompileCore is requestParams[params_.payloadHeader.getRequestCount()].middleware ); - _consumeFees( - params_.payloadHeader.getRequestCount(), - watcherPrecompileLimits__.finalizeFees(params_.payloadHeader.getChainSlug()) + _consumeCallbackFeesFromRequestCount( + watcherPrecompileLimits__.finalizeFees(), + params_.payloadHeader.getRequestCount() ); uint256 deadline = block.timestamp + expiryTime; @@ -119,9 +116,9 @@ 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()) + _consumeCallbackFeesFromRequestCount( + watcherPrecompileLimits__.queryFees(), + params_.payloadHeader.getRequestCount() ); payloads[params_.payloadId].prevDigestsHash = _getPreviousDigestsHash( @@ -254,19 +251,24 @@ abstract contract WatcherPrecompileCore is if (signer != owner()) revert InvalidWatcherSignature(); } - function _consumeFees(uint40 requestCount_, uint256 fees_) internal { - RequestMetadata memory requestMetadata_ = requestMetadata[requestCount_]; - + function _consumeCallbackFeesFromRequestCount(uint256 fees_, uint40 requestCount_) internal { // for callbacks in all precompiles - uint256 feesToConsume = fees_ + watcherPrecompileLimits__().callBackFees(); - IFeesManager(addressResolver__.feesManager()).assignWatcherPrecompileFees( - requestMetadata_.fees.feePoolChain, - requestMetadata_.fees.feePoolToken, + uint256 feesToConsume = fees_ + watcherPrecompileLimits__.callBackFees(); + IFeesManager(addressResolver__.feesManager()).assignWatcherPrecompileFeesFromRequestCount( feesToConsume, requestCount_ ); } + function _consumeCallbackFeesFromAddress(uint256 fees_, address consumeFrom_) internal { + // for callbacks in all precompiles + uint256 feesToConsume = fees_ + watcherPrecompileLimits__.callBackFees(); + IFeesManager(addressResolver__.feesManager()).assignWatcherPrecompileFeesFromAddress( + feesToConsume, + consumeFrom_ + ); + } + /// @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/test/DeliveryHelper.t.sol b/test/DeliveryHelper.t.sol index fd7647d7..45877410 100644 --- a/test/DeliveryHelper.t.sol +++ b/test/DeliveryHelper.t.sol @@ -27,7 +27,7 @@ contract DeliveryHelperTest is SetupTest { uint40 indexed requestCount, address indexed appGateway, PayloadSubmitParams[] payloadSubmitParams, - Fees fees, + uint256 maxFees, address auctionManager, bool onlyReadRequests ); @@ -173,18 +173,14 @@ contract DeliveryHelperTest is SetupTest { //////////////////////////////////// Fees //////////////////////////////////// - function depositFees(address appGateway_, Fees memory fees_) internal { - SocketContracts memory socketConfig = getSocketConfig(fees_.feePoolChain); - socketConfig.feesPlug.deposit{value: fees_.amount}( - fees_.feePoolToken, - appGateway_, - fees_.amount - ); + function depositFees(address appGateway_, OnChainFees memory fees_) internal { + SocketContracts memory socketConfig = getSocketConfig(fees_.chainSlug); + socketConfig.feesPlug.deposit{value: fees_.amount}(fees_.token, appGateway_, fees_.amount); bytes memory bytesInput = abi.encode( - fees_.feePoolChain, + fees_.chainSlug, appGateway_, - fees_.feePoolToken, + fees_.token, fees_.amount ); @@ -193,9 +189,9 @@ contract DeliveryHelperTest is SetupTest { ); bytes memory sig = _createSignature(digest, watcherPrivateKey); feesManager.incrementFeesDeposited( - fees_.feePoolChain, + fees_.chainSlug, appGateway_, - fees_.feePoolToken, + fees_.token, fees_.amount, signatureNonce++, sig diff --git a/test/FeesTest.t.sol b/test/FeesTest.t.sol index ec2f9632..7116c8f4 100644 --- a/test/FeesTest.t.sol +++ b/test/FeesTest.t.sol @@ -19,8 +19,11 @@ contract FeesTest is DeliveryHelperTest { setUpDeliveryHelper(); feesConfig = getSocketConfig(feesChainSlug); - counterGateway = new CounterAppGateway(address(addressResolver), createFees(feesAmount)); - depositFees(address(counterGateway), createFees(depositAmount)); + counterGateway = new CounterAppGateway(address(addressResolver), feesAmount); + depositFees( + address(counterGateway), + OnChainFees({chainSlug: feesChainSlug, token: ETH_ADDRESS, amount: depositAmount}) + ); bytes32[] memory contractIds = new bytes32[](1); contractIds[0] = counterGateway.counter(); diff --git a/test/Inbox.t.sol b/test/Inbox.t.sol index 56d7e45f..cdd3baa7 100644 --- a/test/Inbox.t.sol +++ b/test/Inbox.t.sol @@ -26,7 +26,7 @@ contract TriggerTest is DeliveryHelperTest { counter = new Counter(); // Deploy the gateway with fees - gateway = new CounterAppGateway(address(addressResolver), createFees(feesAmount)); + gateway = new CounterAppGateway(address(addressResolver), feesAmount); gateway.setIsValidPlug(arbChainSlug, address(counter)); // Connect the counter to the gateway and socket diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index 152c1729..d5d699c9 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -19,7 +19,7 @@ import {ContractFactoryPlug} from "../contracts/protocol/payload-delivery/Contra import {FeesPlug} from "../contracts/protocol/payload-delivery/FeesPlug.sol"; import {ETH_ADDRESS} from "../contracts/protocol/utils/common/Constants.sol"; -import {ResolvedPromises} from "../contracts/protocol/utils/common/Structs.sol"; +import {ResolvedPromises, OnChainFees} from "../contracts/protocol/utils/common/Structs.sol"; import "solady/utils/ERC1967Factory.sol"; @@ -283,10 +283,6 @@ contract SetupTest is Test { return chainSlug_ == arbChainSlug ? arbConfig : optConfig; } - function createFees(uint256 maxFees_) internal view returns (Fees memory) { - return Fees({feePoolChain: arbChainSlug, feePoolToken: ETH_ADDRESS, amount: maxFees_}); - } - function _generateWatcherProof( PayloadParams memory params_ ) internal view returns (bytes memory, bytes32) { @@ -403,4 +399,12 @@ contract SetupTest is Test { mstore(add(sig, 64), sigS) } } + + function _createOnChainFees( + uint32 chainSlug_, + address token_, + uint256 amount_ + ) internal returns (OnChainFees memory) { + return OnChainFees({chainSlug: chainSlug_, token: token_, amount: amount_}); + } } diff --git a/test/apps/Counter.t.sol b/test/apps/Counter.t.sol index 243abcfc..92079168 100644 --- a/test/apps/Counter.t.sol +++ b/test/apps/Counter.t.sol @@ -16,8 +16,11 @@ contract CounterTest is DeliveryHelperTest { function deploySetup() internal { setUpDeliveryHelper(); - counterGateway = new CounterAppGateway(address(addressResolver), createFees(feesAmount)); - depositFees(address(counterGateway), createFees(1 ether)); + counterGateway = new CounterAppGateway(address(addressResolver), feesAmount); + depositFees( + address(counterGateway), + OnChainFees({chainSlug: arbChainSlug, token: ETH_ADDRESS, amount: 1 ether}) + ); counterId = counterGateway.counter(); contractIds[0] = counterId; diff --git a/test/apps/ParallelCounter.t.sol b/test/apps/ParallelCounter.t.sol index fdaa8ac4..6cfc28f3 100644 --- a/test/apps/ParallelCounter.t.sol +++ b/test/apps/ParallelCounter.t.sol @@ -16,11 +16,11 @@ contract ParallelCounterTest is DeliveryHelperTest { function deploySetup() internal { setUpDeliveryHelper(); - parallelCounterGateway = new CounterAppGateway( - address(addressResolver), - createFees(feesAmount) + parallelCounterGateway = new CounterAppGateway(address(addressResolver), feesAmount); + depositFees( + address(parallelCounterGateway), + OnChainFees({chainSlug: arbChainSlug, token: ETH_ADDRESS, amount: 1 ether}) ); - depositFees(address(parallelCounterGateway), createFees(1 ether)); counterId1 = parallelCounterGateway.counter1(); counterId2 = parallelCounterGateway.counter(); contractIds[0] = counterId1; diff --git a/test/apps/SuperToken.t.sol b/test/apps/SuperToken.t.sol index f33ca720..97eadc43 100644 --- a/test/apps/SuperToken.t.sol +++ b/test/apps/SuperToken.t.sol @@ -65,7 +65,7 @@ contract SuperTokenTest is DeliveryHelperTest { SuperTokenAppGateway superTokenApp = new SuperTokenAppGateway( address(addressResolver), owner, - createFees(maxFees), + maxFees, SuperTokenAppGateway.ConstructorParams({ name_: "SUPER TOKEN", symbol_: "SUPER", @@ -76,7 +76,10 @@ contract SuperTokenTest is DeliveryHelperTest { ); // Enable app gateways to do all operations in the Watcher: Read, Write and Schedule on EVMx // Watcher sets the limits for apps in this SOCKET protocol version - depositFees(address(superTokenApp), createFees(1 ether)); + depositFees( + address(superTokenApp), + OnChainFees({chainSlug: arbChainSlug, token: ETH_ADDRESS, amount: 1 ether}) + ); appContracts = AppContracts({ superTokenApp: superTokenApp, diff --git a/test/apps/app-gateways/counter/CounterAppGateway.sol b/test/apps/app-gateways/counter/CounterAppGateway.sol index a7b9561b..dc232047 100644 --- a/test/apps/app-gateways/counter/CounterAppGateway.sol +++ b/test/apps/app-gateways/counter/CounterAppGateway.sol @@ -25,7 +25,7 @@ contract CounterAppGateway is AppGatewayBase, Ownable { } // deploy contracts - function deployContracts(uint32 chainSlug_) external async { + function deployContracts(uint32 chainSlug_) external async(address(this)) { _deploy(counter, chainSlug_, IsPlug.YES); } @@ -33,14 +33,14 @@ contract CounterAppGateway is AppGatewayBase, Ownable { _deploy(counter, chainSlug_, IsPlug.YES); } - function deployParallelContracts(uint32 chainSlug_) external async { + function deployParallelContracts(uint32 chainSlug_) external async(address(this)) { _setOverrides(Parallel.ON); _deploy(counter, chainSlug_, IsPlug.YES); _deploy(counter1, chainSlug_, IsPlug.YES); _setOverrides(Parallel.OFF); } - function deployMultiChainContracts(uint32[] memory chainSlugs_) external async { + function deployMultiChainContracts(uint32[] memory chainSlugs_) external async(address(this)) { _setOverrides(Parallel.ON); for (uint32 i = 0; i < chainSlugs_.length; i++) { _deploy(counter, chainSlugs_[i], IsPlug.YES); @@ -53,7 +53,7 @@ contract CounterAppGateway is AppGatewayBase, Ownable { return; } - function incrementCounters(address[] memory instances_) public async { + function incrementCounters(address[] memory instances_) public async(address(this)) { // the increase function is called on given list of instances // this for (uint256 i = 0; i < instances_.length; i++) { @@ -69,7 +69,7 @@ contract CounterAppGateway is AppGatewayBase, Ownable { } } - function readCounters(address[] memory instances_) public async { + function readCounters(address[] memory instances_) public async(address(this)) { // the increase function is called on given list of instances _setOverrides(Read.ON, Parallel.ON); for (uint256 i = 0; i < instances_.length; i++) { @@ -80,7 +80,10 @@ contract CounterAppGateway is AppGatewayBase, Ownable { _setOverrides(Read.OFF, Parallel.OFF); } - function readCounterAtBlock(address instance_, uint256 blockNumber_) public async { + function readCounterAtBlock( + address instance_, + uint256 blockNumber_ + ) public async(address(this)) { uint32 chainSlug = IForwarder(instance_).getChainSlug(); _setOverrides(Read.ON, Parallel.ON, blockNumber_); ICounter(instance_).getCounter(); @@ -120,8 +123,8 @@ contract CounterAppGateway is AppGatewayBase, Ownable { } // UTILS - function setFees(uint256 fees_) public { - fees = fees_; + function setMaxFees(uint256 fees_) public { + maxFees = fees_; } function withdrawFeeTokens( @@ -133,12 +136,12 @@ contract CounterAppGateway is AppGatewayBase, Ownable { return _withdrawFeeTokens(chainSlug_, token_, amount_, receiver_); } - function testOnChainRevert(uint32 chainSlug) public async { + function testOnChainRevert(uint32 chainSlug) public async(address(this)) { address instance = forwarderAddresses[counter][chainSlug]; ICounter(instance).wrongFunction(); } - function testCallBackRevert(uint32 chainSlug) public async { + function testCallBackRevert(uint32 chainSlug) public async(address(this)) { // the increase function is called on given list of instances _setOverrides(Read.ON, Parallel.ON); address instance = forwarderAddresses[counter][chainSlug]; diff --git a/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol b/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol index 58846bc6..c10045e0 100644 --- a/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol +++ b/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol @@ -60,7 +60,7 @@ contract SuperTokenAppGateway is AppGatewayBase, Ownable { return; } - function transfer(bytes memory order_) external async createFeePool { + function transfer(bytes memory order_) external async { TransferOrder memory order = abi.decode(order_, (TransferOrder)); ISuperToken(order.srcToken).burn(order.user, order.srcAmount); ISuperToken(order.dstToken).mint(order.user, order.srcAmount); From f525c117fa3a624ca5b86ad5be3c390e181d188a Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 21 Apr 2025 15:14:48 +0530 Subject: [PATCH 5/7] fix: test build --- contracts/interfaces/IWatcherPrecompileLimits.sol | 1 - .../protocol/payload-delivery/AuctionManager.sol | 14 +++++--------- .../protocol/payload-delivery/FeesManager.sol | 4 +++- .../payload-delivery/app-gateway/RequestQueue.sol | 2 +- .../watcherPrecompile/WatcherPrecompileLimits.sol | 4 ++-- .../watcherPrecompile/core/RequestHandler.sol | 3 +-- .../core/WatcherPrecompileCore.sol | 7 ++++++- 7 files changed, 18 insertions(+), 17 deletions(-) diff --git a/contracts/interfaces/IWatcherPrecompileLimits.sol b/contracts/interfaces/IWatcherPrecompileLimits.sol index 394a8cdc..2bede009 100644 --- a/contracts/interfaces/IWatcherPrecompileLimits.sol +++ b/contracts/interfaces/IWatcherPrecompileLimits.sol @@ -47,7 +47,6 @@ interface IWatcherPrecompileLimits { /// @param limitType_ The type of limit to consume /// @param consumeLimit_ The amount of limit to consume function consumeLimit( - uint40 requestCount_, address appGateway_, bytes32 limitType_, uint256 consumeLimit_ diff --git a/contracts/protocol/payload-delivery/AuctionManager.sol b/contracts/protocol/payload-delivery/AuctionManager.sol index 632a3d15..8e51ba64 100644 --- a/contracts/protocol/payload-delivery/AuctionManager.sol +++ b/contracts/protocol/payload-delivery/AuctionManager.sol @@ -105,7 +105,6 @@ contract AuctionManager is ) external { if (auctionClosed[requestCount_]) revert AuctionClosed(); - RequestMetadata memory requestMetadata = _getRequestMetadata(requestCount_); // check if the transmitter is valid address transmitter = _recoverSigner( keccak256(abi.encode(address(this), evmxSlug, requestCount_, bidFees, extraData)), @@ -113,10 +112,9 @@ contract AuctionManager is ); if (!_hasRole(TRANSMITTER_ROLE, transmitter)) revert InvalidTransmitter(); - (uint256 watcherFees, uint256 transmitterCredits) = getTransmitterMaxFeesRequired( - requestCount_ - // check if the bid exceeds the max fees quoted by app gateway subtracting the watcher fees - ); + uint256 transmitterCredits = getTransmitterMaxFeesRequired(requestCount_); + + // check if the bid exceeds the max fees quoted by app gateway subtracting the watcher fees if (bidFees > transmitterCredits) revert BidExceedsMaxFees(); // check if the bid is lower than the existing bid @@ -210,17 +208,15 @@ contract AuctionManager is function getTransmitterMaxFeesRequired( uint40 requestCount_ - ) public view returns (uint256, uint256) { + ) public view returns (uint256) { RequestMetadata memory requestMetadata = _getRequestMetadata(requestCount_); // check if the bid is for this auction manager if (requestMetadata.auctionManager != address(this)) revert InvalidBid(); - // get the request metadata - // get the total fees required for the watcher precompile ops uint256 watcherFees = watcherPrecompileLimits().getTotalFeesRequired(requestCount_); - return (watcherFees, requestMetadata.maxFees - watcherFees); + return requestMetadata.maxFees - watcherFees; } function _recoverSigner( diff --git a/contracts/protocol/payload-delivery/FeesManager.sol b/contracts/protocol/payload-delivery/FeesManager.sol index 260c4b52..99f59885 100644 --- a/contracts/protocol/payload-delivery/FeesManager.sol +++ b/contracts/protocol/payload-delivery/FeesManager.sol @@ -191,7 +191,7 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol function _processFeeApprovalData( bytes memory feeApprovalData_ - ) internal view returns (address consumeFrom, address appGateway, bool isApproved) { + ) internal returns (address consumeFrom, address appGateway, bool isApproved) { bytes memory signature_; (consumeFrom, appGateway, isApproved, signature_) = abi.decode( feeApprovalData_, @@ -228,11 +228,13 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol isAppGatewayWhitelisted[msg.sender][appGateways_[i]] = true; } } + modifier onlyAuctionManager(uint40 requestCount_) { if (msg.sender != deliveryHelper__().getRequestMetadata(requestCount_).auctionManager) revert NotAuctionManager(); _; } + /// @notice Blocks fees for a request count /// @param consumeFrom_ The fees payer address /// @param transmitterCredits_ The total fees to block diff --git a/contracts/protocol/payload-delivery/app-gateway/RequestQueue.sol b/contracts/protocol/payload-delivery/app-gateway/RequestQueue.sol index dac1a41d..f88ac9cd 100644 --- a/contracts/protocol/payload-delivery/app-gateway/RequestQueue.sol +++ b/contracts/protocol/payload-delivery/app-gateway/RequestQueue.sol @@ -37,7 +37,7 @@ abstract contract RequestQueue is DeliveryUtils { address appGateway_, bytes memory feesApprovalData_, uint256 maxFees_ - ) internal view returns (address consumeFrom) { + ) internal returns (address consumeFrom) { if (queuePayloadParams.length > REQUEST_PAYLOAD_COUNT_LIMIT) revert RequestPayloadCountLimitExceeded(); (consumeFrom, , ) = IFeesManager(addressResolver__.feesManager()).setAppGatewayWhitelist( diff --git a/contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol b/contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol index 89e99779..f933b29a 100644 --- a/contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol +++ b/contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol @@ -57,6 +57,7 @@ contract WatcherPrecompileLimits is event DefaultLimitAndRatePerSecondSet(uint256 defaultLimit, uint256 defaultRatePerSecond); error WatcherFeesNotSet(bytes32 limitType); + /// @notice Initial initialization (version 1) function initialize( address owner_, @@ -130,7 +131,6 @@ contract WatcherPrecompileLimits is * @param consumeLimit_ The amount of limit to consume */ function consumeLimit( - uint40 requestCount_, address appGateway_, bytes32 limitType_, uint256 consumeLimit_ @@ -155,7 +155,7 @@ contract WatcherPrecompileLimits is } // Update the limit - precompileCount[limitType_][requestCount_] += consumeLimit_; + // precompileCount[limitType_][requestCount_] += consumeLimit_; _consumeFullLimit(consumeLimit_ * 10 ** limitDecimals, limitParams); } diff --git a/contracts/protocol/watcherPrecompile/core/RequestHandler.sol b/contracts/protocol/watcherPrecompile/core/RequestHandler.sol index f89e36e5..c0508f71 100644 --- a/contracts/protocol/watcherPrecompile/core/RequestHandler.sol +++ b/contracts/protocol/watcherPrecompile/core/RequestHandler.sol @@ -15,13 +15,12 @@ abstract contract RequestHandler is WatcherPrecompileCore { /// @notice Submits a batch of payload requests from middleware /// @param payloadSubmitParams_ Array of payload submit parameters - /// @param requestMetadata_ Request metadata /// @return requestCount The unique identifier for the submitted request /// @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_, - RequestMetadata calldata requestMetadata_ + RequestMetadata calldata ) public returns (uint40 requestCount) { address appGateway = _checkAppGateways(payloadSubmitParams_); diff --git a/contracts/protocol/watcherPrecompile/core/WatcherPrecompileCore.sol b/contracts/protocol/watcherPrecompile/core/WatcherPrecompileCore.sol index da6c919d..2e0a6d5a 100644 --- a/contracts/protocol/watcherPrecompile/core/WatcherPrecompileCore.sol +++ b/contracts/protocol/watcherPrecompile/core/WatcherPrecompileCore.sol @@ -7,6 +7,7 @@ import {AccessControl} from "../../utils/AccessControl.sol"; import "solady/utils/Initializable.sol"; import {AddressResolverUtil} from "../../utils/AddressResolverUtil.sol"; import {IFeesManager} from "../../../interfaces/IFeesManager.sol"; + /// @title WatcherPrecompileCore /// @notice Core functionality for the WatcherPrecompile system /// @dev This contract implements the core functionality for payload verification, execution, and app configurations @@ -50,7 +51,11 @@ abstract contract WatcherPrecompileCore is ); // consumes limit for SCHEDULE precompile - watcherPrecompileLimits__.consumeLimit(_getCoreAppGateway(msg.sender), SCHEDULE, 1); + watcherPrecompileLimits__.consumeLimit( + _getCoreAppGateway(msg.sender), + SCHEDULE, + 1 + ); // emits event for watcher to track timeout and resolve when timeout is reached emit TimeoutRequested(timeoutId, msg.sender, payload_, executeAt); From c38aeeb768926825c295815123d9f6168b615bd1 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 21 Apr 2025 15:22:23 +0530 Subject: [PATCH 6/7] fix: script and test build --- script/counter/SetFees.s.sol | 2 +- .../counter/WithdrawFeesArbitrumFeesPlug.s.sol | 6 +----- script/helpers/AppGatewayFeeBalance.s.sol | 17 +++++------------ script/helpers/PayFeesInArbitrumETH.s.sol | 2 +- test/DeliveryHelper.t.sol | 4 ++-- test/FeesTest.t.sol | 3 ++- test/SetupTest.t.sol | 2 +- .../app-gateways/counter/CounterAppGateway.sol | 16 ++++++++-------- .../super-token/SuperTokenAppGateway.sol | 4 ++-- 9 files changed, 23 insertions(+), 33 deletions(-) diff --git a/script/counter/SetFees.s.sol b/script/counter/SetFees.s.sol index e48d9a73..3f87f4ac 100644 --- a/script/counter/SetFees.s.sol +++ b/script/counter/SetFees.s.sol @@ -22,6 +22,6 @@ contract CounterSetFees is Script { console.log("Setting fees..."); // Setting fee payment on Arbitrum Sepolia uint256 fees = 0.00001 ether; - appGateway.setFees(fees); + // appGateway.setFees(fees); } } diff --git a/script/counter/WithdrawFeesArbitrumFeesPlug.s.sol b/script/counter/WithdrawFeesArbitrumFeesPlug.s.sol index 3a78e9cf..b2b50a25 100644 --- a/script/counter/WithdrawFeesArbitrumFeesPlug.s.sol +++ b/script/counter/WithdrawFeesArbitrumFeesPlug.s.sol @@ -17,11 +17,7 @@ contract WithdrawFees is Script { address appGatewayAddress = vm.envAddress("APP_GATEWAY"); CounterAppGateway appGateway = CounterAppGateway(appGatewayAddress); - uint256 availableFees = feesManager.getAvailableFees( - 421614, - appGatewayAddress, - ETH_ADDRESS - ); + uint256 availableFees = feesManager.getAvailableFees(appGatewayAddress); console.log("Available fees:", availableFees); if (availableFees > 0) { diff --git a/script/helpers/AppGatewayFeeBalance.s.sol b/script/helpers/AppGatewayFeeBalance.s.sol index a1faade9..d2ba38d8 100644 --- a/script/helpers/AppGatewayFeeBalance.s.sol +++ b/script/helpers/AppGatewayFeeBalance.s.sol @@ -11,21 +11,14 @@ contract CheckDepositedFees is Script { vm.createSelectFork(vm.envString("EVMX_RPC")); FeesManager feesManager = FeesManager(payable(vm.envAddress("FEES_MANAGER"))); address appGateway = vm.envAddress("APP_GATEWAY"); - uint32 chain = 421614; - address token = ETH_ADDRESS; - (uint256 deposited, uint256 blocked) = feesManager.userFeeBalances( - appGateway, - chain, - token - ); + + (uint256 totalCredits, uint256 blockedCredits) = feesManager.userCredits(appGateway); console.log("App Gateway:", appGateway); console.log("Fees Manager:", address(feesManager)); - console.logUint(chain); - console.log("Token:", token); - console.log("Deposited fees:", deposited); - console.log("Blocked fees:", blocked); + console.log("totalCredits fees:", totalCredits); + console.log("blockedCredits fees:", blockedCredits); - uint256 availableFees = feesManager.getAvailableFees(chain, appGateway, token); + uint256 availableFees = feesManager.getAvailableFees(appGateway); console.log("Available fees:", availableFees); } } diff --git a/script/helpers/PayFeesInArbitrumETH.s.sol b/script/helpers/PayFeesInArbitrumETH.s.sol index 6fbd7164..9bf56848 100644 --- a/script/helpers/PayFeesInArbitrumETH.s.sol +++ b/script/helpers/PayFeesInArbitrumETH.s.sol @@ -23,6 +23,6 @@ contract DepositFees is Script { console.log("App Gateway:", appGateway); console.log("Fees Plug:", address(feesPlug)); uint feesAmount = 0.001 ether; - feesPlug.deposit{value: feesAmount}(ETH_ADDRESS, appGateway, feesAmount); + feesPlug.depositToFeeAndNative(ETH_ADDRESS, feesAmount, appGateway); } } diff --git a/test/DeliveryHelper.t.sol b/test/DeliveryHelper.t.sol index 45877410..e915a59d 100644 --- a/test/DeliveryHelper.t.sol +++ b/test/DeliveryHelper.t.sol @@ -175,7 +175,7 @@ contract DeliveryHelperTest is SetupTest { function depositFees(address appGateway_, OnChainFees memory fees_) internal { SocketContracts memory socketConfig = getSocketConfig(fees_.chainSlug); - socketConfig.feesPlug.deposit{value: fees_.amount}(fees_.token, appGateway_, fees_.amount); + socketConfig.feesPlug.depositToFeeAndNative(fees_.token, fees_.amount, appGateway_); bytes memory bytesInput = abi.encode( fees_.chainSlug, @@ -189,8 +189,8 @@ contract DeliveryHelperTest is SetupTest { ); bytes memory sig = _createSignature(digest, watcherPrivateKey); feesManager.incrementFeesDeposited( - fees_.chainSlug, appGateway_, + fees_.chainSlug, fees_.token, fees_.amount, signatureNonce++, diff --git a/test/FeesTest.t.sol b/test/FeesTest.t.sol index 7116c8f4..4755cb15 100644 --- a/test/FeesTest.t.sol +++ b/test/FeesTest.t.sol @@ -51,7 +51,8 @@ contract FeesTest is DeliveryHelperTest { uint40 requestCount = feesManager.withdrawTransmitterFees( feesChainSlug, ETH_ADDRESS, - address(receiver) + address(receiver), + feesManager.transmitterCredits(transmitterEOA) ); uint40[] memory batches = watcherPrecompile.getBatches(requestCount); _finalizeBatch(batches[0], new bytes[](0), 0, false); diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index d5d699c9..69237ec1 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -404,7 +404,7 @@ contract SetupTest is Test { uint32 chainSlug_, address token_, uint256 amount_ - ) internal returns (OnChainFees memory) { + ) internal pure returns (OnChainFees memory) { return OnChainFees({chainSlug: chainSlug_, token: token_, amount: amount_}); } } diff --git a/test/apps/app-gateways/counter/CounterAppGateway.sol b/test/apps/app-gateways/counter/CounterAppGateway.sol index dc232047..eb5e6e7e 100644 --- a/test/apps/app-gateways/counter/CounterAppGateway.sol +++ b/test/apps/app-gateways/counter/CounterAppGateway.sol @@ -25,7 +25,7 @@ contract CounterAppGateway is AppGatewayBase, Ownable { } // deploy contracts - function deployContracts(uint32 chainSlug_) external async(address(this)) { + function deployContracts(uint32 chainSlug_) external async(bytes("")) { _deploy(counter, chainSlug_, IsPlug.YES); } @@ -33,14 +33,14 @@ contract CounterAppGateway is AppGatewayBase, Ownable { _deploy(counter, chainSlug_, IsPlug.YES); } - function deployParallelContracts(uint32 chainSlug_) external async(address(this)) { + function deployParallelContracts(uint32 chainSlug_) external async(bytes("")) { _setOverrides(Parallel.ON); _deploy(counter, chainSlug_, IsPlug.YES); _deploy(counter1, chainSlug_, IsPlug.YES); _setOverrides(Parallel.OFF); } - function deployMultiChainContracts(uint32[] memory chainSlugs_) external async(address(this)) { + function deployMultiChainContracts(uint32[] memory chainSlugs_) external async(bytes("")) { _setOverrides(Parallel.ON); for (uint32 i = 0; i < chainSlugs_.length; i++) { _deploy(counter, chainSlugs_[i], IsPlug.YES); @@ -53,7 +53,7 @@ contract CounterAppGateway is AppGatewayBase, Ownable { return; } - function incrementCounters(address[] memory instances_) public async(address(this)) { + function incrementCounters(address[] memory instances_) public async(bytes("")) { // the increase function is called on given list of instances // this for (uint256 i = 0; i < instances_.length; i++) { @@ -69,7 +69,7 @@ contract CounterAppGateway is AppGatewayBase, Ownable { } } - function readCounters(address[] memory instances_) public async(address(this)) { + function readCounters(address[] memory instances_) public async(bytes("")) { // the increase function is called on given list of instances _setOverrides(Read.ON, Parallel.ON); for (uint256 i = 0; i < instances_.length; i++) { @@ -83,7 +83,7 @@ contract CounterAppGateway is AppGatewayBase, Ownable { function readCounterAtBlock( address instance_, uint256 blockNumber_ - ) public async(address(this)) { + ) public async(bytes("")) { uint32 chainSlug = IForwarder(instance_).getChainSlug(); _setOverrides(Read.ON, Parallel.ON, blockNumber_); ICounter(instance_).getCounter(); @@ -136,12 +136,12 @@ contract CounterAppGateway is AppGatewayBase, Ownable { return _withdrawFeeTokens(chainSlug_, token_, amount_, receiver_); } - function testOnChainRevert(uint32 chainSlug) public async(address(this)) { + function testOnChainRevert(uint32 chainSlug) public async(bytes("")) { address instance = forwarderAddresses[counter][chainSlug]; ICounter(instance).wrongFunction(); } - function testCallBackRevert(uint32 chainSlug) public async(address(this)) { + function testCallBackRevert(uint32 chainSlug) public async(bytes("")) { // the increase function is called on given list of instances _setOverrides(Read.ON, Parallel.ON); address instance = forwarderAddresses[counter][chainSlug]; diff --git a/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol b/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol index c10045e0..8e38065d 100644 --- a/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol +++ b/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol @@ -49,7 +49,7 @@ contract SuperTokenAppGateway is AppGatewayBase, Ownable { _initializeOwner(owner_); } - function deployContracts(uint32 chainSlug_) external async { + function deployContracts(uint32 chainSlug_) external async(bytes("")) { bytes memory initData = abi.encodeWithSelector(SuperToken.setOwner.selector, owner()); _deploy(superToken, chainSlug_, IsPlug.YES, initData); } @@ -60,7 +60,7 @@ contract SuperTokenAppGateway is AppGatewayBase, Ownable { return; } - function transfer(bytes memory order_) external async { + function transfer(bytes memory order_) external async(bytes("")) { TransferOrder memory order = abi.decode(order_, (TransferOrder)); ISuperToken(order.srcToken).burn(order.user, order.srcAmount); ISuperToken(order.dstToken).mint(order.user, order.srcAmount); From 8c48ba3697e6ba8d503fa8a842da46a19f1713ca Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 21 Apr 2025 21:01:24 +0530 Subject: [PATCH 7/7] wip: consume limit --- contracts/protocol/utils/common/Structs.sol | 3 +++ .../WatcherPrecompileLimits.sol | 20 ++++++++----------- .../watcherPrecompile/core/RequestHandler.sol | 5 ++++- .../core/WatcherPrecompileCore.sol | 1 + 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/contracts/protocol/utils/common/Structs.sol b/contracts/protocol/utils/common/Structs.sol index 4dcffff9..118d772d 100644 --- a/contracts/protocol/utils/common/Structs.sol +++ b/contracts/protocol/utils/common/Structs.sol @@ -210,6 +210,9 @@ struct RequestParams { // updated while processing request uint256 currentBatchPayloadsLeft; uint256 payloadsRemaining; + uint256 queryCount; + uint256 finalizeCount; + uint256 scheduleCount; address middleware; // updated after auction address transmitter; diff --git a/contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol b/contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol index f933b29a..f0f2921a 100644 --- a/contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol +++ b/contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol @@ -43,10 +43,6 @@ contract WatcherPrecompileLimits is // Mapping to track active app gateways mapping(address => bool) internal _activeAppGateways; - // slot 156: precompileCount - // limitType => requestCount => count - mapping(bytes32 => mapping(uint40 => uint256)) public precompileCount; - // slot 157: fees uint256 public queryFees; uint256 public finalizeFees; @@ -155,8 +151,6 @@ contract WatcherPrecompileLimits is } // Update the limit - // precompileCount[limitType_][requestCount_] += consumeLimit_; - _consumeFullLimit(consumeLimit_ * 10 ** limitDecimals, limitParams); } @@ -202,14 +196,16 @@ contract WatcherPrecompileLimits is revert WatcherFeesNotSet(CALLBACK); } - uint256 totalCallbacks = precompileCount[QUERY][requestCount_] + - precompileCount[FINALIZE][requestCount_] + - precompileCount[SCHEDULE][requestCount_]; + uint256 queryCount = watcherPrecompile__().requestParams[requestCount_].queryCount; + uint256 finalizeCount = watcherPrecompile__().requestParams[requestCount_].finalizeCount; + uint256 scheduleCount = watcherPrecompile__().requestParams[requestCount_].scheduleCount; + + uint256 totalCallbacks = queryCount + finalizeCount + scheduleCount; totalFees += totalCallbacks * callBackFees; - totalFees += precompileCount[QUERY][requestCount_] * queryFees; - totalFees += precompileCount[FINALIZE][requestCount_] * finalizeFees; - totalFees += precompileCount[SCHEDULE][requestCount_] * scheduleFees; + totalFees += queryCount * queryFees; + totalFees += finalizeCount * finalizeFees; + totalFees += scheduleCount * scheduleFees; return totalFees; } diff --git a/contracts/protocol/watcherPrecompile/core/RequestHandler.sol b/contracts/protocol/watcherPrecompile/core/RequestHandler.sol index c0508f71..e6b32c08 100644 --- a/contracts/protocol/watcherPrecompile/core/RequestHandler.sol +++ b/contracts/protocol/watcherPrecompile/core/RequestHandler.sol @@ -20,7 +20,7 @@ abstract contract RequestHandler is WatcherPrecompileCore { /// @dev It also consumes limits for the app gateway based on the number of reads and writes function submitRequest( PayloadSubmitParams[] calldata payloadSubmitParams_, - RequestMetadata calldata + RequestMetadata calldata requestMetadata_ ) public returns (uint40 requestCount) { address appGateway = _checkAppGateways(payloadSubmitParams_); @@ -93,6 +93,9 @@ abstract contract RequestHandler is WatcherPrecompileCore { watcherPrecompileLimits__.consumeLimit(appGateway, QUERY, readCount); watcherPrecompileLimits__.consumeLimit(appGateway, FINALIZE, writeCount); + requestParams[requestCount].queryCount = readCount; + requestParams[requestCount].finalizeCount = writeCount; + requestParams[requestCount].currentBatch = currentBatch; requestParams[requestCount].payloadsRemaining = payloadSubmitParams_.length; requestParams[requestCount].middleware = msg.sender; diff --git a/contracts/protocol/watcherPrecompile/core/WatcherPrecompileCore.sol b/contracts/protocol/watcherPrecompile/core/WatcherPrecompileCore.sol index 2e0a6d5a..53928cd8 100644 --- a/contracts/protocol/watcherPrecompile/core/WatcherPrecompileCore.sol +++ b/contracts/protocol/watcherPrecompile/core/WatcherPrecompileCore.sol @@ -56,6 +56,7 @@ abstract contract WatcherPrecompileCore is SCHEDULE, 1 ); + // emits event for watcher to track timeout and resolve when timeout is reached emit TimeoutRequested(timeoutId, msg.sender, payload_, executeAt);