@@ -29,7 +29,6 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver,
2929
3030 error TokenNotSupported (address token );
3131 error FeeTokenNotSupported (address token );
32- error ChainNotSupported (uint64 chain );
3332 error StaleGasPrice (uint64 destChainSelector , uint256 threshold , uint256 timePassed );
3433 error StaleKeystoneUpdate (address token , uint256 feedTimestamp , uint256 storedTimeStamp );
3534 error DataFeedValueOutOfUint224Range ();
@@ -76,7 +75,8 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver,
7675 struct StaticConfig {
7776 uint96 maxFeeJuelsPerMsg; // ─╮ Maximum fee that can be charged for a message
7877 address linkToken; // ────────╯ LINK token address
79- uint32 stalenessThreshold; // The amount of time a gas price can be stale before it is considered invalid.
78+ // The amount of time a token price can be stale before it is considered invalid (gas price staleness is configured per dest chain)
79+ uint32 tokenPriceStalenessThreshold;
8080 }
8181
8282 /// @dev The struct representing the received CCIP feed report from keystone IReceiver.onReport()
@@ -103,6 +103,7 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver,
103103 uint32 defaultTxGasLimit; //─────────────────╮ Default gas limit for a tx
104104 uint64 gasMultiplierWeiPerEth; // │ Multiplier for gas costs, 1e18 based so 11e17 = 10% extra cost.
105105 uint32 networkFeeUSDCents; // │ Flat network fee to charge for messages, multiples of 0.01 USD
106+ uint32 gasPriceStalenessThreshold; // │ The amount of time a gas price can be stale before it is considered invalid (0 means disabled)
106107 bool enforceOutOfOrder; // │ Whether to enforce the allowOutOfOrderExecution extraArg value to be true.
107108 bytes4 chainFamilySelector; // ──────────────╯ Selector that identifies the destination chain's family. Used to determine the correct validations to perform for the dest chain.
108109 }
@@ -202,8 +203,8 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver,
202203
203204 /// @dev Subset of tokens which prices tracked by this registry which are fee tokens.
204205 EnumerableSet.AddressSet private s_feeTokens;
205- /// @dev The amount of time a gas price can be stale before it is considered invalid.
206- uint32 private immutable i_stalenessThreshold ;
206+ /// @dev The amount of time a token price can be stale before it is considered invalid.
207+ uint32 private immutable i_tokenPriceStalenessThreshold ;
207208
208209 constructor (
209210 StaticConfig memory staticConfig ,
@@ -216,14 +217,14 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver,
216217 ) AuthorizedCallers (priceUpdaters) {
217218 if (
218219 staticConfig.linkToken == address (0 ) || staticConfig.maxFeeJuelsPerMsg == 0
219- || staticConfig.stalenessThreshold == 0
220+ || staticConfig.tokenPriceStalenessThreshold == 0
220221 ) {
221222 revert InvalidStaticConfig ();
222223 }
223224
224225 i_linkToken = staticConfig.linkToken;
225226 i_maxFeeJuelsPerMsg = staticConfig.maxFeeJuelsPerMsg;
226- i_stalenessThreshold = staticConfig.stalenessThreshold ;
227+ i_tokenPriceStalenessThreshold = staticConfig.tokenPriceStalenessThreshold ;
227228
228229 _applyFeeTokensUpdates (feeTokens, new address [](0 ));
229230 _updateTokenPriceFeeds (tokenPriceFeeds);
@@ -241,7 +242,7 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver,
241242 Internal.TimestampedPackedUint224 memory tokenPrice = s_usdPerToken[token];
242243
243244 // If the token price is not stale, return it
244- if (block .timestamp - tokenPrice.timestamp < i_stalenessThreshold ) {
245+ if (block .timestamp - tokenPrice.timestamp < i_tokenPriceStalenessThreshold ) {
245246 return tokenPrice;
246247 }
247248
@@ -305,14 +306,12 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver,
305306 function getTokenAndGasPrices (
306307 address token ,
307308 uint64 destChainSelector
308- ) public view returns (uint224 tokenPrice , uint224 gasPriceValue ) {
309- Internal.TimestampedPackedUint224 memory gasPrice = s_usdPerUnitGasByDestChainSelector[destChainSelector];
310- // We do allow a gas price of 0, but no stale or unset gas prices
311- if (gasPrice.timestamp == 0 ) revert ChainNotSupported (destChainSelector);
312- uint256 timePassed = block .timestamp - gasPrice.timestamp;
313- if (timePassed > i_stalenessThreshold) revert StaleGasPrice (destChainSelector, i_stalenessThreshold, timePassed);
314-
315- return (_getValidatedTokenPrice (token), gasPrice.value);
309+ ) external view returns (uint224 tokenPrice , uint224 gasPriceValue ) {
310+ if (! s_destChainConfigs[destChainSelector].isEnabled) revert DestinationChainNotEnabled (destChainSelector);
311+ return (
312+ _getValidatedTokenPrice (token),
313+ _getValidatedGasPrice (destChainSelector, s_destChainConfigs[destChainSelector].gasPriceStalenessThreshold)
314+ );
316315 }
317316
318317 /// @notice Convert a given token amount to target token amount.
@@ -374,6 +373,27 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver,
374373 return Internal.TimestampedPackedUint224 ({value: rebasedValue, timestamp: uint32 (block .timestamp )});
375374 }
376375
376+ /// @dev Gets the fee token price and the gas price, both denominated in dollars.
377+ /// @param destChainSelector The destination chain to get the gas price for.
378+ /// @param gasPriceStalenessThreshold The amount of time a gas price can be stale before it is considered invalid.
379+ /// @return gasPriceValue The price of gas in 1e18 dollars per base unit.
380+ function _getValidatedGasPrice (
381+ uint64 destChainSelector ,
382+ uint32 gasPriceStalenessThreshold
383+ ) private view returns (uint224 gasPriceValue ) {
384+ Internal.TimestampedPackedUint224 memory gasPrice = s_usdPerUnitGasByDestChainSelector[destChainSelector];
385+ // If the staleness threshold is 0, we consider the gas price to be always valid
386+ if (gasPriceStalenessThreshold != 0 ) {
387+ // We do allow a gas price of 0, but no stale or unset gas prices
388+ uint256 timePassed = block .timestamp - gasPrice.timestamp;
389+ if (timePassed > gasPriceStalenessThreshold) {
390+ revert StaleGasPrice (destChainSelector, gasPriceStalenessThreshold, timePassed);
391+ }
392+ }
393+
394+ return gasPrice.value;
395+ }
396+
377397 // ================================================================
378398 // │ Fee tokens │
379399 // ================================================================
@@ -507,7 +527,8 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver,
507527 _validateMessage (destChainConfig, message.data.length , numberOfTokens, message.receiver);
508528
509529 // The below call asserts that feeToken is a supported token
510- (uint224 feeTokenPrice , uint224 packedGasPrice ) = getTokenAndGasPrices (message.feeToken, destChainSelector);
530+ uint224 feeTokenPrice = _getValidatedTokenPrice (message.feeToken);
531+ uint224 packedGasPrice = _getValidatedGasPrice (destChainSelector, destChainConfig.gasPriceStalenessThreshold);
511532
512533 // Calculate premiumFee in USD with 18 decimals precision first.
513534 // If message-only and no token transfers, a flat network fee is charged.
@@ -990,7 +1011,7 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver,
9901011 return StaticConfig ({
9911012 maxFeeJuelsPerMsg: i_maxFeeJuelsPerMsg,
9921013 linkToken: i_linkToken,
993- stalenessThreshold: i_stalenessThreshold
1014+ tokenPriceStalenessThreshold: i_tokenPriceStalenessThreshold
9941015 });
9951016 }
9961017}
0 commit comments