Skip to content
This repository was archived by the owner on Mar 14, 2025. It is now read-only.

Commit 5e3277e

Browse files
committed
adding wrappers
1 parent 249ca62 commit 5e3277e

File tree

15 files changed

+3620
-24
lines changed

15 files changed

+3620
-24
lines changed
Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
pragma solidity 0.8.24;
3+
4+
import {ITypeAndVersion} from "../shared/interfaces/ITypeAndVersion.sol";
5+
import {IPriceRegistry} from "./interfaces/IPriceRegistry.sol";
6+
7+
import {OwnerIsCreator} from "./../shared/access/OwnerIsCreator.sol";
8+
import {Internal} from "./libraries/Internal.sol";
9+
import {USDPriceWith18Decimals} from "./libraries/USDPriceWith18Decimals.sol";
10+
11+
import {EnumerableSet} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol";
12+
13+
/// @notice The PriceRegistry contract responsibility is to store the current gas price in USD for a given destination chain,
14+
/// and the price of a token in USD allowing the owner or priceUpdater to update this value.
15+
contract PriceRegistry is IPriceRegistry, OwnerIsCreator, ITypeAndVersion {
16+
using EnumerableSet for EnumerableSet.AddressSet;
17+
using USDPriceWith18Decimals for uint224;
18+
19+
error TokenNotSupported(address token);
20+
error ChainNotSupported(uint64 chain);
21+
error OnlyCallableByUpdaterOrOwner();
22+
error StaleGasPrice(uint64 destChainSelector, uint256 threshold, uint256 timePassed);
23+
error StaleTokenPrice(address token, uint256 threshold, uint256 timePassed);
24+
error InvalidStalenessThreshold();
25+
26+
event PriceUpdaterSet(address indexed priceUpdater);
27+
event PriceUpdaterRemoved(address indexed priceUpdater);
28+
event FeeTokenAdded(address indexed feeToken);
29+
event FeeTokenRemoved(address indexed feeToken);
30+
event UsdPerUnitGasUpdated(uint64 indexed destChain, uint256 value, uint256 timestamp);
31+
event UsdPerTokenUpdated(address indexed token, uint256 value, uint256 timestamp);
32+
33+
// solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables
34+
string public constant override typeAndVersion = "PriceRegistry 1.2.0";
35+
36+
/// @dev The gas price per unit of gas for a given destination chain, in USD with 18 decimals.
37+
/// Multiple gas prices can be encoded into the same value. Each price takes {Internal.GAS_PRICE_BITS} bits.
38+
/// For example, if Optimism is the destination chain, gas price can include L1 base fee and L2 gas price.
39+
/// Logic to parse the price components is chain-specific, and should live in OnRamp.
40+
/// @dev Price of 1e18 is 1 USD. Examples:
41+
/// Very Expensive: 1 unit of gas costs 1 USD -> 1e18
42+
/// Expensive: 1 unit of gas costs 0.1 USD -> 1e17
43+
/// Cheap: 1 unit of gas costs 0.000001 USD -> 1e12
44+
mapping(uint64 destChainSelector => Internal.TimestampedPackedUint224 price)
45+
private s_usdPerUnitGasByDestChainSelector;
46+
47+
/// @dev The price, in USD with 18 decimals, per 1e18 of the smallest token denomination.
48+
/// @dev Price of 1e18 represents 1 USD per 1e18 token amount.
49+
/// 1 USDC = 1.00 USD per full token, each full token is 1e6 units -> 1 * 1e18 * 1e18 / 1e6 = 1e30
50+
/// 1 ETH = 2,000 USD per full token, each full token is 1e18 units -> 2000 * 1e18 * 1e18 / 1e18 = 2_000e18
51+
/// 1 LINK = 5.00 USD per full token, each full token is 1e18 units -> 5 * 1e18 * 1e18 / 1e18 = 5e18
52+
mapping(address token => Internal.TimestampedPackedUint224 price) private s_usdPerToken;
53+
54+
// Price updaters are allowed to update the prices.
55+
EnumerableSet.AddressSet private s_priceUpdaters;
56+
// Subset of tokens which prices tracked by this registry which are fee tokens.
57+
EnumerableSet.AddressSet private s_feeTokens;
58+
// The amount of time a price can be stale before it is considered invalid.
59+
uint32 private immutable i_stalenessThreshold;
60+
61+
constructor(address[] memory priceUpdaters, address[] memory feeTokens, uint32 stalenessThreshold) {
62+
_applyPriceUpdatersUpdates(priceUpdaters, new address[](0));
63+
_applyFeeTokensUpdates(feeTokens, new address[](0));
64+
if (stalenessThreshold == 0) revert InvalidStalenessThreshold();
65+
i_stalenessThreshold = stalenessThreshold;
66+
}
67+
68+
// ================================================================
69+
// │ Price calculations │
70+
// ================================================================
71+
72+
// @inheritdoc IPriceRegistry
73+
function getTokenPrice(address token) public view override returns (Internal.TimestampedPackedUint224 memory) {
74+
return s_usdPerToken[token];
75+
}
76+
77+
// @inheritdoc IPriceRegistry
78+
function getValidatedTokenPrice(address token) external view override returns (uint224) {
79+
return _getValidatedTokenPrice(token);
80+
}
81+
82+
// @inheritdoc IPriceRegistry
83+
function getTokenPrices(
84+
address[] calldata tokens
85+
) external view override returns (Internal.TimestampedPackedUint224[] memory) {
86+
uint256 length = tokens.length;
87+
Internal.TimestampedPackedUint224[] memory tokenPrices = new Internal.TimestampedPackedUint224[](length);
88+
for (uint256 i = 0; i < length; ++i) {
89+
tokenPrices[i] = getTokenPrice(tokens[i]);
90+
}
91+
return tokenPrices;
92+
}
93+
94+
/// @notice Get the staleness threshold.
95+
/// @return stalenessThreshold The staleness threshold.
96+
function getStalenessThreshold() external view returns (uint128) {
97+
return i_stalenessThreshold;
98+
}
99+
100+
// @inheritdoc IPriceRegistry
101+
function getDestinationChainGasPrice(
102+
uint64 destChainSelector
103+
) external view override returns (Internal.TimestampedPackedUint224 memory) {
104+
return s_usdPerUnitGasByDestChainSelector[destChainSelector];
105+
}
106+
107+
function getTokenAndGasPrices(
108+
address token,
109+
uint64 destChainSelector
110+
) external view override returns (uint224 tokenPrice, uint224 gasPriceValue) {
111+
Internal.TimestampedPackedUint224 memory gasPrice = s_usdPerUnitGasByDestChainSelector[destChainSelector];
112+
// We do allow a gas price of 0, but no stale or unset gas prices
113+
if (gasPrice.timestamp == 0) revert ChainNotSupported(destChainSelector);
114+
uint256 timePassed = block.timestamp - gasPrice.timestamp;
115+
if (timePassed > i_stalenessThreshold) revert StaleGasPrice(destChainSelector, i_stalenessThreshold, timePassed);
116+
117+
return (_getValidatedTokenPrice(token), gasPrice.value);
118+
}
119+
120+
/// @inheritdoc IPriceRegistry
121+
/// @dev this function assumes that no more than 1e59 dollars are sent as payment.
122+
/// If more is sent, the multiplication of feeTokenAmount and feeTokenValue will overflow.
123+
/// Since there isn't even close to 1e59 dollars in the world economy this is safe.
124+
function convertTokenAmount(
125+
address fromToken,
126+
uint256 fromTokenAmount,
127+
address toToken
128+
) external view override returns (uint256) {
129+
/// Example:
130+
/// fromTokenAmount: 1e18 // 1 ETH
131+
/// ETH: 2_000e18
132+
/// LINK: 5e18
133+
/// return: 1e18 * 2_000e18 / 5e18 = 400e18 (400 LINK)
134+
return (fromTokenAmount * _getValidatedTokenPrice(fromToken)) / _getValidatedTokenPrice(toToken);
135+
}
136+
137+
/// @notice Gets the token price for a given token and revert if the token is either
138+
/// not supported or the price is stale.
139+
/// @param token The address of the token to get the price for
140+
/// @return the token price
141+
function _getValidatedTokenPrice(address token) internal view returns (uint224) {
142+
Internal.TimestampedPackedUint224 memory tokenPrice = s_usdPerToken[token];
143+
if (tokenPrice.timestamp == 0 || tokenPrice.value == 0) revert TokenNotSupported(token);
144+
uint256 timePassed = block.timestamp - tokenPrice.timestamp;
145+
if (timePassed > i_stalenessThreshold) revert StaleTokenPrice(token, i_stalenessThreshold, timePassed);
146+
return tokenPrice.value;
147+
}
148+
149+
// ================================================================
150+
// │ Fee tokens │
151+
// ================================================================
152+
153+
/// @notice Get the list of fee tokens.
154+
/// @return The tokens set as fee tokens.
155+
function getFeeTokens() external view returns (address[] memory) {
156+
return s_feeTokens.values();
157+
}
158+
159+
/// @notice Add and remove tokens from feeTokens set.
160+
/// @param feeTokensToAdd The addresses of the tokens which are now considered fee tokens
161+
/// and can be used to calculate fees.
162+
/// @param feeTokensToRemove The addresses of the tokens which are no longer considered feeTokens.
163+
function applyFeeTokensUpdates(
164+
address[] memory feeTokensToAdd,
165+
address[] memory feeTokensToRemove
166+
) external onlyOwner {
167+
_applyFeeTokensUpdates(feeTokensToAdd, feeTokensToRemove);
168+
}
169+
170+
/// @notice Add and remove tokens from feeTokens set.
171+
/// @param feeTokensToAdd The addresses of the tokens which are now considered fee tokens
172+
/// and can be used to calculate fees.
173+
/// @param feeTokensToRemove The addresses of the tokens which are no longer considered feeTokens.
174+
function _applyFeeTokensUpdates(address[] memory feeTokensToAdd, address[] memory feeTokensToRemove) private {
175+
for (uint256 i = 0; i < feeTokensToAdd.length; ++i) {
176+
if (s_feeTokens.add(feeTokensToAdd[i])) {
177+
emit FeeTokenAdded(feeTokensToAdd[i]);
178+
}
179+
}
180+
for (uint256 i = 0; i < feeTokensToRemove.length; ++i) {
181+
if (s_feeTokens.remove(feeTokensToRemove[i])) {
182+
emit FeeTokenRemoved(feeTokensToRemove[i]);
183+
}
184+
}
185+
}
186+
187+
// ================================================================
188+
// │ Price updates │
189+
// ================================================================
190+
191+
// @inheritdoc IPriceRegistry
192+
function updatePrices(Internal.PriceUpdates calldata priceUpdates) external override requireUpdaterOrOwner {
193+
uint256 tokenUpdatesLength = priceUpdates.tokenPriceUpdates.length;
194+
195+
for (uint256 i = 0; i < tokenUpdatesLength; ++i) {
196+
Internal.TokenPriceUpdate memory update = priceUpdates.tokenPriceUpdates[i];
197+
s_usdPerToken[update.sourceToken] = Internal.TimestampedPackedUint224({
198+
value: update.usdPerToken,
199+
timestamp: uint32(block.timestamp)
200+
});
201+
emit UsdPerTokenUpdated(update.sourceToken, update.usdPerToken, block.timestamp);
202+
}
203+
204+
uint256 gasUpdatesLength = priceUpdates.gasPriceUpdates.length;
205+
206+
for (uint256 i = 0; i < gasUpdatesLength; ++i) {
207+
Internal.GasPriceUpdate memory update = priceUpdates.gasPriceUpdates[i];
208+
s_usdPerUnitGasByDestChainSelector[update.destChainSelector] = Internal.TimestampedPackedUint224({
209+
value: update.usdPerUnitGas,
210+
timestamp: uint32(block.timestamp)
211+
});
212+
emit UsdPerUnitGasUpdated(update.destChainSelector, update.usdPerUnitGas, block.timestamp);
213+
}
214+
}
215+
216+
// ================================================================
217+
// │ Access │
218+
// ================================================================
219+
220+
/// @notice Get the list of price updaters.
221+
/// @return The price updaters.
222+
function getPriceUpdaters() external view returns (address[] memory) {
223+
return s_priceUpdaters.values();
224+
}
225+
226+
/// @notice Adds new priceUpdaters and remove existing ones.
227+
/// @param priceUpdatersToAdd The addresses of the priceUpdaters that are now allowed
228+
/// to send fee updates.
229+
/// @param priceUpdatersToRemove The addresses of the priceUpdaters that are no longer allowed
230+
/// to send fee updates.
231+
function applyPriceUpdatersUpdates(
232+
address[] memory priceUpdatersToAdd,
233+
address[] memory priceUpdatersToRemove
234+
) external onlyOwner {
235+
_applyPriceUpdatersUpdates(priceUpdatersToAdd, priceUpdatersToRemove);
236+
}
237+
238+
/// @notice Adds new priceUpdaters and remove existing ones.
239+
/// @param priceUpdatersToAdd The addresses of the priceUpdaters that are now allowed
240+
/// to send fee updates.
241+
/// @param priceUpdatersToRemove The addresses of the priceUpdaters that are no longer allowed
242+
/// to send fee updates.
243+
function _applyPriceUpdatersUpdates(
244+
address[] memory priceUpdatersToAdd,
245+
address[] memory priceUpdatersToRemove
246+
) private {
247+
for (uint256 i = 0; i < priceUpdatersToAdd.length; ++i) {
248+
if (s_priceUpdaters.add(priceUpdatersToAdd[i])) {
249+
emit PriceUpdaterSet(priceUpdatersToAdd[i]);
250+
}
251+
}
252+
for (uint256 i = 0; i < priceUpdatersToRemove.length; ++i) {
253+
if (s_priceUpdaters.remove(priceUpdatersToRemove[i])) {
254+
emit PriceUpdaterRemoved(priceUpdatersToRemove[i]);
255+
}
256+
}
257+
}
258+
259+
/// @notice Require that the caller is the owner or a fee updater.
260+
modifier requireUpdaterOrOwner() {
261+
if (msg.sender != owner() && !s_priceUpdaters.contains(msg.sender)) revert OnlyCallableByUpdaterOrOwner();
262+
_;
263+
}
264+
}

core/gethwrappers/ccip/generated/commit_store/commit_store.go

Lines changed: 99 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/gethwrappers/ccip/generated/evm_2_evm_offramp/evm_2_evm_offramp.go

Lines changed: 99 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/gethwrappers/ccip/generated/evm_2_evm_onramp/evm_2_evm_onramp.go

Lines changed: 99 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/gethwrappers/ccip/generated/fee_quoter/fee_quoter.go

Lines changed: 99 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)