Skip to content

Commit

Permalink
CCIP-3723 Modify TokenPriceFeedConfig to support future tokens with z…
Browse files Browse the repository at this point in the history
…ero decimals (#14809)

* CCIP-3723 Modify TokenPriceFeedConfig to support future tokens with zero decimals

* [Bot] Update changeset file with jira issues

* Update gethwrappers

* Update gethwrappers

* snapshot fixes

* gas snapshot CI errors keep me awake at night

* fill in missing test and remove unneeded changeset file

* Update gethwrappers

* undo CI issues caused from mege conflict resolution

* delete unnec. snapshot file.

* Update gethwrappers

* ccip-precommit attempts

* Update FeeQuoter.sol

* [Bot] Update changeset file with jira issues

* fix compiler error from merge conflict resolution

* forge fmt

* Update gethwrappers

* update comments & add extra check

---------

Co-authored-by: app-token-issuer-infra-releng[bot] <120227048+app-token-issuer-infra-releng[bot]@users.noreply.github.com>
Co-authored-by: Rens Rooimans <[email protected]>
  • Loading branch information
3 people authored Oct 24, 2024
1 parent 101fbbc commit 082e6fc
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 183 deletions.
10 changes: 10 additions & 0 deletions contracts/.changeset/ninety-coins-mate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@chainlink/contracts': patch
---

Modified TokenPriceFeedConfig to support tokens with zero decimals #bugfix


PR issue: CCIP-3723

Solidity Review issue: CCIP-3966
333 changes: 167 additions & 166 deletions contracts/gas-snapshots/ccip.gas-snapshot

Large diffs are not rendered by default.

21 changes: 12 additions & 9 deletions contracts/src/v0.8/ccip/FeeQuoter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,11 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver,
event DestChainConfigUpdated(uint64 indexed destChainSelector, DestChainConfig destChainConfig);
event DestChainAdded(uint64 indexed destChainSelector, DestChainConfig destChainConfig);

/// @dev Token price data feed configuration
/// @dev Contains token price configuration used in both the keystone price updates and the price feed fallback logic.
struct TokenPriceFeedConfig {
address dataFeedAddress; // ─╮ AggregatorV3Interface contract (0 - feed is unset)
uint8 tokenDecimals; // ─────╯ Decimals of the token that the feed represents
address dataFeedAddress; // ──╮ Price feed contract. Can be address(0) to indicate no feed is configured.
uint8 tokenDecimals; // | Decimals of the token, used for both keystone and price feed decimal multiplications.
bool isEnabled; // ───────────╯ Whether the token is configured to receive keystone and/or price feed updates.
}

/// @dev Token price data feed update
Expand Down Expand Up @@ -248,16 +249,16 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver,
return tokenPrice;
}

// When we have a stale price we should check if there is a more up to date source. If not, return the stale price.
TokenPriceFeedConfig memory priceFeedConfig = s_usdPriceFeedsPerToken[token];

// If the token price feed is not set, return the stale price
if (priceFeedConfig.dataFeedAddress == address(0)) {
if (!priceFeedConfig.isEnabled || priceFeedConfig.dataFeedAddress == address(0)) {
return tokenPrice;
}

// If the token price feed is set, retrieve the price from the feed
Internal.TimestampedPackedUint224 memory feedPrice = _getTokenPriceFromDataFeed(priceFeedConfig);

// We check if the feed price isn't more stale than the stored price. Return the most recent one.
return feedPrice.timestamp >= tokenPrice.timestamp ? feedPrice : tokenPrice;
}

Expand Down Expand Up @@ -507,12 +508,14 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver,
ReceivedCCIPFeedReport[] memory feeds = abi.decode(report, (ReceivedCCIPFeedReport[]));

for (uint256 i = 0; i < feeds.length; ++i) {
uint8 tokenDecimals = s_usdPriceFeedsPerToken[feeds[i].token].tokenDecimals;
if (tokenDecimals == 0) {
TokenPriceFeedConfig memory feedConfig = s_usdPriceFeedsPerToken[feeds[i].token];

if (!feedConfig.isEnabled) {
revert TokenNotSupported(feeds[i].token);
}
// Keystone reports prices in USD with 18 decimals, so we passing it as 18 in the _calculateRebasedValue function
uint224 rebasedValue = _calculateRebasedValue(uint8(KEYSTONE_PRICE_DECIMALS), tokenDecimals, feeds[i].price);
uint224 rebasedValue =
_calculateRebasedValue(uint8(KEYSTONE_PRICE_DECIMALS), feedConfig.tokenDecimals, feeds[i].price);

//if stale update then revert
if (feeds[i].timestamp < s_usdPerToken[feeds[i].token].timestamp) {
Expand Down
17 changes: 15 additions & 2 deletions contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoter.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2218,11 +2218,11 @@ contract FeeQuoter_KeystoneSetup is FeeQuoterSetup {
FeeQuoter.TokenPriceFeedUpdate[] memory tokenPriceFeeds = new FeeQuoter.TokenPriceFeedUpdate[](2);
tokenPriceFeeds[0] = FeeQuoter.TokenPriceFeedUpdate({
sourceToken: onReportTestToken1,
feedConfig: FeeQuoter.TokenPriceFeedConfig({dataFeedAddress: address(0x0), tokenDecimals: 18})
feedConfig: FeeQuoter.TokenPriceFeedConfig({dataFeedAddress: address(0x0), tokenDecimals: 18, isEnabled: true})
});
tokenPriceFeeds[1] = FeeQuoter.TokenPriceFeedUpdate({
sourceToken: onReportTestToken2,
feedConfig: FeeQuoter.TokenPriceFeedConfig({dataFeedAddress: address(0x0), tokenDecimals: 20})
feedConfig: FeeQuoter.TokenPriceFeedConfig({dataFeedAddress: address(0x0), tokenDecimals: 20, isEnabled: true})
});
s_feeQuoter.setReportPermissions(permissions);
s_feeQuoter.updateTokenPriceFeeds(tokenPriceFeeds);
Expand Down Expand Up @@ -2257,6 +2257,19 @@ contract FeeQuoter_onReport is FeeQuoter_KeystoneSetup {
vm.assertEq(s_feeQuoter.getTokenPrice(report[1].token).timestamp, report[1].timestamp);
}

function test_onReport_TokenNotSupported_Revert() public {
bytes memory encodedPermissionsMetadata =
abi.encodePacked(keccak256(abi.encode("workflowCID")), WORKFLOW_NAME_1, WORKFLOW_OWNER_1, REPORT_NAME_1);
FeeQuoter.ReceivedCCIPFeedReport[] memory report = new FeeQuoter.ReceivedCCIPFeedReport[](1);
report[0] =
FeeQuoter.ReceivedCCIPFeedReport({token: s_sourceTokens[1], price: 4e18, timestamp: uint32(block.timestamp)});

// Revert due to token config not being set with the isEnabled flag
vm.expectRevert(abi.encodeWithSelector(FeeQuoter.TokenNotSupported.selector, s_sourceTokens[1]));
vm.startPrank(FORWARDER_1);
s_feeQuoter.onReport(encodedPermissionsMetadata, abi.encode(report));
}

function test_onReport_InvalidForwarder_Reverts() public {
bytes memory encodedPermissionsMetadata =
abi.encodePacked(keccak256(abi.encode("workflowCID")), WORKFLOW_NAME_1, WORKFLOW_OWNER_1, REPORT_NAME_1);
Expand Down
9 changes: 7 additions & 2 deletions contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoterSetup.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,11 @@ contract FeeQuoterSetup is TokenSetup {
) internal pure returns (FeeQuoter.TokenPriceFeedUpdate memory) {
return FeeQuoter.TokenPriceFeedUpdate({
sourceToken: sourceToken,
feedConfig: FeeQuoter.TokenPriceFeedConfig({dataFeedAddress: dataFeedAddress, tokenDecimals: tokenDecimals})
feedConfig: FeeQuoter.TokenPriceFeedConfig({
dataFeedAddress: dataFeedAddress,
tokenDecimals: tokenDecimals,
isEnabled: true
})
});
}

Expand Down Expand Up @@ -268,13 +272,14 @@ contract FeeQuoterSetup is TokenSetup {
) internal pure virtual {
assertEq(config1.dataFeedAddress, config2.dataFeedAddress);
assertEq(config1.tokenDecimals, config2.tokenDecimals);
assertEq(config1.isEnabled, config2.isEnabled);
}

function _assertTokenPriceFeedConfigUnconfigured(
FeeQuoter.TokenPriceFeedConfig memory config
) internal pure virtual {
_assertTokenPriceFeedConfigEquality(
config, FeeQuoter.TokenPriceFeedConfig({dataFeedAddress: address(0), tokenDecimals: 0})
config, FeeQuoter.TokenPriceFeedConfig({dataFeedAddress: address(0), tokenDecimals: 0, isEnabled: false})
);
}

Expand Down
7 changes: 4 additions & 3 deletions core/gethwrappers/ccip/generated/fee_quoter/fee_quoter.go

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ ccip_encoding_utils: ../../../contracts/solc/v0.8.24/ICCIPEncodingUtils/ICCIPEnc
ccip_home: ../../../contracts/solc/v0.8.24/CCIPHome/CCIPHome.abi ../../../contracts/solc/v0.8.24/CCIPHome/CCIPHome.bin 8c603a0de19c4649d69bdd18774ee3b5edfd24c696aabdb7cdb982bd8e304829
ccip_reader_tester: ../../../contracts/solc/v0.8.24/CCIPReaderTester/CCIPReaderTester.abi ../../../contracts/solc/v0.8.24/CCIPReaderTester/CCIPReaderTester.bin 5db06eb7fad07ec0d1ae5ac8d39f61398687fe3cda8290716ce0cd8fb9dca1ab
ether_sender_receiver: ../../../contracts/solc/v0.8.24/EtherSenderReceiver/EtherSenderReceiver.abi ../../../contracts/solc/v0.8.24/EtherSenderReceiver/EtherSenderReceiver.bin 09510a3f773f108a3c231e8d202835c845ded862d071ec54c4f89c12d868b8de
fee_quoter: ../../../contracts/solc/v0.8.24/FeeQuoter/FeeQuoter.abi ../../../contracts/solc/v0.8.24/FeeQuoter/FeeQuoter.bin 3eb799751e92bb09cf94c8ad9245c620026c3a8a0a0fffee8c3921f8fcd37eb8
fee_quoter: ../../../contracts/solc/v0.8.24/FeeQuoter/FeeQuoter.abi ../../../contracts/solc/v0.8.24/FeeQuoter/FeeQuoter.bin 0d069b7b8c240c326fdb54ff53b222dea455939ff31e8e87dff1133806a638e4
lock_release_token_pool: ../../../contracts/solc/v0.8.24/LockReleaseTokenPool/LockReleaseTokenPool.abi ../../../contracts/solc/v0.8.24/LockReleaseTokenPool/LockReleaseTokenPool.bin e6a8ec9e8faccb1da7d90e0f702ed72975964f97dc3222b54cfcca0a0ba3fea2
maybe_revert_message_receiver: ../../../contracts/solc/v0.8.24/MaybeRevertMessageReceiver/MaybeRevertMessageReceiver.abi ../../../contracts/solc/v0.8.24/MaybeRevertMessageReceiver/MaybeRevertMessageReceiver.bin d73956c26232ebcc4a5444429fa99cbefed960e323be9b5a24925885c2e477d5
message_hasher: ../../../contracts/solc/v0.8.24/MessageHasher/MessageHasher.abi ../../../contracts/solc/v0.8.24/MessageHasher/MessageHasher.bin ec2d3a92348d8e7b8f0d359b62a45157b9d2c750c01fbcf991826c4392f6e218
Expand Down

0 comments on commit 082e6fc

Please sign in to comment.