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 82422aae..3f252074 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 maxFees; mapping(address => bool) public isValidPromise; mapping(bytes32 => mapping(uint32 => address)) public override forwarderAddresses; @@ -29,20 +29,19 @@ 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 - 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, FeesPlugin return address(0); } - onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]).getOnChainAddress(); + onChainAddress = IForwarder(forwarderAddresses[contractId_][chainSlug_]) + .getOnChainAddress(); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -197,19 +197,19 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway, FeesPlugin /// @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( Read isReadCall_, Parallel isParallelCall_, uint256 gasLimit_, - Fees memory fees_ + uint256 fees_ ) internal { 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, FeesPlugin 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, FeesPlugin overrideParams.value = value_; } - /// @notice Sets fees overrides - /// @param fees_ The fees configuration - function _setOverrides(Fees memory 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, FeesPlugin 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, FeesPlugin amount_, receiver_, auctionManager, - fees + maxFees ); } 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..71b0eb70 100644 --- a/contracts/interfaces/IFeesManager.sol +++ b/contracts/interfaces/IFeesManager.sol @@ -1,29 +1,24 @@ // 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_, - Bid memory winningBid_, + address consumeFrom_, + uint256 transmitterCredits_, uint40 requestCount_ ) external; function unblockFees(uint40 requestCount_) external; function isFeesEnough( - address appGateway_, address consumeFrom_, - Fees memory 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 ce949529..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, Fees, WriteFinality, CallType, Parallel, IsPlug, RequestMetadata, } 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 @@ -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/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..2bede009 100644 --- a/contracts/interfaces/IWatcherPrecompileLimits.sol +++ b/contracts/interfaces/IWatcherPrecompileLimits.sol @@ -46,14 +46,19 @@ 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( + 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 43b8e0fe..8e51ba64 100644 --- a/contracts/protocol/payload-delivery/AuctionManager.sol +++ b/contracts/protocol/payload-delivery/AuctionManager.sol @@ -95,11 +95,11 @@ 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 { @@ -107,26 +107,24 @@ contract AuctionManager is // 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, - requestCount_ - ); + uint256 transmitterCredits = getTransmitterMaxFeesRequired(requestCount_); + // 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; @@ -142,15 +140,6 @@ contract AuctionManager is _endAuction(requestCount_); } - // block the fees - IFeesManager(addressResolver__.feesManager()).blockFees( - requestMetadata.consumeFrom, - requestMetadata.fees, - newBid, - watcherFees, - requestCount_ - ); - emit BidPlaced(requestCount_, newBid); } @@ -167,6 +156,13 @@ 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, + winningBid.fee, + requestCount_ + ); // set the timeout for the bid expiration // useful in case a transmitter did bid but did not execute payloads @@ -211,19 +207,16 @@ contract AuctionManager is } function getTransmitterMaxFeesRequired( - address token_, 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 - 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 requestMetadata.maxFees - watcherFees; } function _recoverSigner( @@ -234,4 +227,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 9b8d96ea..99f59885 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, Fees, CallType, Parallel, WriteFinality, TokenBalance, QueuePayloadParams, IsPlug, PayloadSubmitParams, RequestParams, RequestMetadata} 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 @@ -25,34 +25,38 @@ 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; + // user nonce + mapping(address => uint256) public userNonce; + + // 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 => uint256) 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; @@ -64,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 @@ -83,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 @@ -152,61 +145,80 @@ 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 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 depositTo_, uint32 chainSlug_, - address originAppGateway_, address token_, uint256 amount_, uint256 signatureNonce_, bytes memory signature_ ) external { _isWatcherSignatureValid( - abi.encode(chainSlug_, originAppGateway_, token_, amount_), + abi.encode(depositTo_, chainSlug_, token_, amount_), signatureNonce_, signature_ ); - address appGateway = _getCoreAppGateway(originAppGateway_); + UserCredits storage userCredit = userCredits[depositTo_]; + 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(chainSlug_, depositTo_, token_, amount_); } function isFeesEnough( - address originAppGateway_, address consumeFrom_, - Fees memory fees_ + address appGateway_, + 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 + if (!isAppGatewayWhitelisted[consumeFrom_][appGateway_]) return false; + return getAvailableFees(consumeFrom_) >= amount_; + } + + function _processFeeApprovalData( + bytes memory feeApprovalData_ + ) internal 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 + ) ); - return availableFees >= fees_.amount; + 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 @@ -217,56 +229,32 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol } } + modifier onlyAuctionManager(uint40 requestCount_) { + if (msg.sender != deliveryHelper__().getRequestMetadata(requestCount_).auctionManager) + revert NotAuctionManager(); + _; + } + /// @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 transmitterCredits_ 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 transmitterCredits_, uint40 requestCount_ - ) external { - if (msg.sender != deliveryHelper__().getRequestMetadata(requestCount_).auctionManager) - revert NotAuctionManager(); - + ) external onlyAuctionManager(requestCount_) { // Block fees - uint256 availableFees = getAvailableFees( - feesGivenByApp_.feePoolChain, - consumeFrom_, - feesGivenByApp_.feePoolToken - ); - - if (requestCountBlockedFees[requestCount_].amount > 0) - availableFees += requestCountBlockedFees[requestCount_].amount; + if (getAvailableFees(consumeFrom_) < transmitterCredits_) + revert InsufficientFeesAvailable(); - uint256 feesNeeded = winningBid_.fee + watcherFees_; - if (availableFees < feesNeeded) revert InsufficientFeesAvailable(); + UserCredits storage userCredit = userCredits[consumeFrom_]; + userCredit.blockedCredits += transmitterCredits_; - TokenBalance storage tokenBalance = userFeeBalances[consumeFrom_][ - feesGivenByApp_.feePoolChain - ][feesGivenByApp_.feePoolToken]; + requestCountCredits[requestCount_] = transmitterCredits_; - tokenBalance.blocked = - tokenBalance.blocked + - feesNeeded - - requestCountBlockedFees[requestCount_].amount; - - requestCountBlockedFees[requestCount_] = Fees({ - feePoolChain: feesGivenByApp_.feePoolChain, - feePoolToken: feesGivenByApp_.feePoolToken, - amount: feesNeeded - }); - requestCountConsumeFrom[requestCount_] = consumeFrom_; - - emit FeesBlocked( - requestCount_, - feesGivenByApp_.feePoolChain, - feesGivenByApp_.feePoolToken, - feesNeeded - ); + emit FeesBlocked(requestCount_, consumeFrom_, transmitterCredits_); } /// @notice Unblocks fees after successful execution and assigns them to the transmitter @@ -276,45 +264,63 @@ contract FeesManager is FeesManagerStorage, Initializable, Ownable, AddressResol uint40 requestCount_, address transmitter_ ) external override onlyDeliveryHelper { - Fees memory fees = requestCountBlockedFees[requestCount_]; - if (fees.amount == 0) return; - + uint256 blockedCredits = requestCountCredits[requestCount_]; + if (blockedCredits == 0) return; RequestMetadata memory requestMetadata = deliveryHelper__().getRequestMetadata( requestCount_ ); - - TokenBalance storage tokenBalance = userFeeBalances[consumeFrom][fees.feePoolChain][ - fees.feePoolToken - ]; - - uint256 transmitterBid = requestMetadata.winningBid.fee; - uint256 remainingFees = fees.amount - transmitterBid; + uint256 fees = requestMetadata.winningBid.fee; // Unblock fees from deposit - tokenBalance.blocked -= fees.amount; - tokenBalance.deposited -= transmitterBid; - tokenBalance.deposited -= remainingFees; + _useBlockedUserCredits(requestMetadata.consumeFrom, blockedCredits, fees); // Assign fees to transmitter - transmitterFees[transmitter_][fees.feePoolChain][fees.feePoolToken] += transmitterBid; + transmitterCredits[transmitter_] += fees; // Clean up storage - delete requestCountBlockedFees[requestCount_]; - emit FeesUnblockedAndAssigned(requestCount_, transmitter_, fees.amount); + delete requestCountCredits[requestCount_]; + emit FeesUnblockedAndAssigned(requestCount_, transmitter_, fees); } - function assignWatcherPrecompileFees( - uint32 chainSlug_, - address token_, - uint256 amount_, + function _useBlockedUserCredits( + address consumeFrom_, + uint256 toConsumeFromBlocked_, + uint256 toConsumeFromTotal_ + ) internal { + UserCredits storage userCredit = userCredits[consumeFrom_]; + userCredit.blockedCredits -= toConsumeFromBlocked_; + userCredit.totalCredits -= toConsumeFromTotal_; + } + + function _useAvailableUserCredits(address consumeFrom_, uint256 toConsume_) internal { + UserCredits storage userCredit = userCredits[consumeFrom_]; + userCredit.totalCredits -= toConsume_; + } + + function assignWatcherPrecompileFeesFromRequestCount( + uint256 fees_, uint40 requestCount_ ) external onlyWatcherPrecompile { - Fees storage fees = requestCountBlockedFees[requestCount_]; - if (fees.amount == 0) revert NoFeesBlocked(); + require(requestCount_ != 0, "Request count cannot be 0"); + RequestMetadata memory requestMetadata = deliveryHelper__().getRequestMetadata( + requestCount_ + ); + _assignWatcherPrecompileFees(fees_, requestMetadata.consumeFrom); + } + + function assignWatcherPrecompileFeesFromAddress( + uint256 fees_, + address consumeFrom_ + ) external onlyWatcherPrecompile { + _assignWatcherPrecompileFees(fees_, consumeFrom_); + } - fees.amount -= amount_; - watcherPrecompileFees[chainSlug_][token_] += amount_; - emit WatcherPrecompileFeesAssigned(chainSlug_, token_, amount_, requestCount_); + function _assignWatcherPrecompileFees(uint256 fees_, address consumeFrom_) internal { + // deduct the fees from the user + _useAvailableUserCredits(consumeFrom_, fees_); + // add the fees to the watcher precompile + watcherPrecompileCredits += fees_; + emit WatcherPrecompileFeesAssigned(fees_, consumeFrom_); } function unblockFees(uint40 requestCount_) external { @@ -327,52 +333,20 @@ 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]; + uint256 blockedCredits = requestCountCredits[requestCount_]; + if (blockedCredits == 0) return; // Unblock fees from deposit - tokenBalance.blocked -= fees.amount; - tokenBalance.deposited += fees.amount; - - delete requestCountBlockedFees[requestCount_]; - emit FeesUnblocked(requestCount_, requestMetadata.appGateway); - } - - /// @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_ - ) 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(); - - // Clean up storage - transmitterFees[transmitter][chainSlug_][token_] = 0; - - // Create fee distribution payload - bytes32 feesId = _encodeFeesId(feesCounter++); - bytes memory payload = abi.encodeCall( - IFeesPlug.distributeFee, - (token_, totalFees, receiver_, feesId) - ); + UserCredits storage userCredit = userCredits[requestMetadata.consumeFrom]; + userCredit.blockedCredits -= blockedCredits; - // finalize for plug contract - return _submitAndStartProcessing(chainSlug_, payload, transmitter); + delete requestCountCredits[requestCount_]; + emit FeesUnblocked(requestCount_, requestMetadata.consumeFrom); } /// @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 @@ -388,21 +362,40 @@ 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_))); } - 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, @@ -417,19 +410,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: Fees({token: token_, amount: 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 773ceb7d..ab6784ce 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_); } @@ -118,28 +107,18 @@ 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_, uint256 feeAmount_, uint256 nativeAmount_ - ) internal override { + ) internal { 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 {} } 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/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..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_); } @@ -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, @@ -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 (Fees memory) { - return requests[requestCount_].fees; + function getFees(uint40 requestCount_) external view returns (uint256) { + 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 be9cabf7..f88ac9cd 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( - Fees memory fees_, + uint256 maxFees_, 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_, maxFees_, feesApprovalData_, onCompleteData_); } function _checkBatch( address appGateway_, bytes memory feesApprovalData_, - Fees memory fees_ - ) internal view { + uint256 maxFees_ + ) internal 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_, - Fees memory fees_, + uint256 maxFees_, bytes memory feesApprovalData_, bytes memory onCompleteData_ ) internal returns (uint40 requestCount) { @@ -77,19 +81,22 @@ 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 - requestCount = watcherPrecompile__().submitRequest(payloadSubmitParamsArray, requestMetadata); + requestCount = watcherPrecompile__().submitRequest( + payloadSubmitParamsArray, + requestMetadata + ); requests[requestCount] = requestMetadata; // send query directly if request contains only reads @@ -98,14 +105,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 = maxFees_ - + watcherPrecompileLimits().getTotalFeesRequired(requestCount); emit PayloadSubmitted( requestCount, appGateway_, payloadSubmitParamsArray, - Fees({token: fees_.token, amount: fees_.amount - 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/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/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 32170560..118d772d 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,11 +124,9 @@ struct OverrideParams { uint256 readAt; } -// FM: -struct Fees { - uint32 feePoolChain; - address feePoolToken; - uint256 amount; +struct UserCredits { + uint256 totalCredits; + uint256 blockedCredits; } // digest: @@ -206,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; @@ -215,11 +222,11 @@ struct RequestParams { struct RequestMetadata { address appGateway; address auctionManager; - Fees fees; + uint256 maxFees; Bid winningBid; bytes onCompleteData; bool onlyReadRequests; - bytes feesApprovalData; + address consumeFrom; } struct ExecuteParams { @@ -237,9 +244,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 -} diff --git a/contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol b/contracts/protocol/watcherPrecompile/WatcherPrecompileLimits.sol index 0ab07deb..f0f2921a 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,15 +43,16 @@ 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 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( @@ -126,7 +127,6 @@ contract WatcherPrecompileLimits is * @param consumeLimit_ The amount of limit to consume */ function consumeLimit( - uint40 requestCount_, address appGateway_, bytes32 limitType_, uint256 consumeLimit_ @@ -151,8 +151,6 @@ contract WatcherPrecompileLimits is } // Update the limit - precompileCount[limitType_][requestCount_] += consumeLimit_; - _consumeFullLimit(consumeLimit_ * 10 ** limitDecimals, limitParams); } @@ -167,63 +165,47 @@ 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 queryCount = watcherPrecompile__().requestParams[requestCount_].queryCount; + uint256 finalizeCount = watcherPrecompile__().requestParams[requestCount_].finalizeCount; + uint256 scheduleCount = watcherPrecompile__().requestParams[requestCount_].scheduleCount; - uint256 totalCallbacks = precompileCount[QUERY][requestCount_] + - precompileCount[FINALIZE][requestCount_] + - precompileCount[SCHEDULE][requestCount_]; + uint256 totalCallbacks = queryCount + finalizeCount + scheduleCount; - 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 += 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 3d00e32d..e6b32c08 100644 --- a/contracts/protocol/watcherPrecompile/core/RequestHandler.sol +++ b/contracts/protocol/watcherPrecompile/core/RequestHandler.sol @@ -14,15 +14,15 @@ 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 /// @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 +32,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) { @@ -93,12 +93,13 @@ 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].payloadsRemaining = payloadSubmitParams_.length; requestParams[requestCount].middleware = msg.sender; - requestMetadata[requestCount] = requestMetadata; - emit RequestSubmitted( msg.sender, requestCount, @@ -132,17 +133,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 78f6f102..bcea7bd0 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_); @@ -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..53928cd8 100644 --- a/contracts/protocol/watcherPrecompile/core/WatcherPrecompileCore.sol +++ b/contracts/protocol/watcherPrecompile/core/WatcherPrecompileCore.sol @@ -6,6 +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 @@ -33,10 +34,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(); @@ -53,7 +51,12 @@ 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); @@ -79,9 +82,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 +122,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 +257,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/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..3f87f4ac 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 - }); - appGateway.setFees(fees); + uint256 fees = 0.00001 ether; + // 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 9bf7c2c9..d2ba38d8 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 { @@ -12,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 edb8b2fd..9bf56848 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 @@ -24,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 fd7647d7..e915a59d 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.depositToFeeAndNative(fees_.token, fees_.amount, appGateway_); 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, appGateway_, - fees_.feePoolToken, + fees_.chainSlug, + fees_.token, fees_.amount, signatureNonce++, sig diff --git a/test/FeesTest.t.sol b/test/FeesTest.t.sol index ec2f9632..4755cb15 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(); @@ -48,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/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..69237ec1 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 pure 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 a27b2db1..eb5e6e7e 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_); @@ -25,7 +25,7 @@ contract CounterAppGateway is AppGatewayBase, Ownable { } // deploy contracts - function deployContracts(uint32 chainSlug_) external async { + 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 { + 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 { + 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 { + 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 { + 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++) { @@ -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(bytes("")) { 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(Fees memory 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(bytes("")) { address instance = forwarderAddresses[counter][chainSlug]; ICounter(instance).wrongFunction(); } - function testCallBackRevert(uint32 chainSlug) public async { + 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 98488499..8e38065d 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( @@ -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 createFeePool { + 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);