编译器
0.8.19+commit.7dd6d404
文件 1 的 11:Client.sol
pragma solidity ^0.8.0;
library Client {
struct EVMTokenAmount {
address token;
uint256 amount;
}
struct Any2EVMMessage {
bytes32 messageId;
uint64 sourceChainSelector;
bytes sender;
bytes data;
EVMTokenAmount[] destTokenAmounts;
}
struct EVM2AnyMessage {
bytes receiver;
bytes data;
EVMTokenAmount[] tokenAmounts;
address feeToken;
bytes extraArgs;
}
bytes4 public constant EVM_EXTRA_ARGS_V1_TAG = 0x97a657c9;
struct EVMExtraArgsV1 {
uint256 gasLimit;
bool strict;
}
function _argsToBytes(EVMExtraArgsV1 memory extraArgs) internal pure returns (bytes memory bts) {
return abi.encodeWithSelector(EVM_EXTRA_ARGS_V1_TAG, extraArgs);
}
}
文件 2 的 11:ConfirmedOwner.sol
pragma solidity ^0.8.0;
import "./ConfirmedOwnerWithProposal.sol";
contract ConfirmedOwner is ConfirmedOwnerWithProposal {
constructor(address newOwner) ConfirmedOwnerWithProposal(newOwner, address(0)) {}
}
文件 3 的 11:ConfirmedOwnerWithProposal.sol
pragma solidity ^0.8.0;
import "./interfaces/OwnableInterface.sol";
contract ConfirmedOwnerWithProposal is OwnableInterface {
address private s_owner;
address private s_pendingOwner;
event OwnershipTransferRequested(address indexed from, address indexed to);
event OwnershipTransferred(address indexed from, address indexed to);
constructor(address newOwner, address pendingOwner) {
require(newOwner != address(0), "Cannot set owner to zero");
s_owner = newOwner;
if (pendingOwner != address(0)) {
_transferOwnership(pendingOwner);
}
}
function transferOwnership(address to) public override onlyOwner {
_transferOwnership(to);
}
function acceptOwnership() external override {
require(msg.sender == s_pendingOwner, "Must be proposed owner");
address oldOwner = s_owner;
s_owner = msg.sender;
s_pendingOwner = address(0);
emit OwnershipTransferred(oldOwner, msg.sender);
}
function owner() public view override returns (address) {
return s_owner;
}
function _transferOwnership(address to) private {
require(to != msg.sender, "Cannot transfer to self");
s_pendingOwner = to;
emit OwnershipTransferRequested(s_owner, to);
}
function _validateOwnership() internal view {
require(msg.sender == s_owner, "Only callable by owner");
}
modifier onlyOwner() {
_validateOwnership();
_;
}
}
文件 4 的 11:EnumerableSet.sol
pragma solidity ^0.8.0;
library EnumerableSet {
struct Set {
bytes32[] _values;
mapping(bytes32 => uint256) _indexes;
}
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
function _remove(Set storage set, bytes32 value) private returns (bool) {
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
set._values[toDeleteIndex] = lastValue;
set._indexes[lastValue] = valueIndex;
}
set._values.pop();
delete set._indexes[value];
return true;
} else {
return false;
}
}
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
struct Bytes32Set {
Set _inner;
}
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
assembly {
result := store
}
return result;
}
struct AddressSet {
Set _inner;
}
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
assembly {
result := store
}
return result;
}
struct UintSet {
Set _inner;
}
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
assembly {
result := store
}
return result;
}
}
文件 5 的 11:IPriceRegistry.sol
pragma solidity ^0.8.0;
import {Internal} from "../libraries/Internal.sol";
interface IPriceRegistry {
function updatePrices(Internal.PriceUpdates memory priceUpdates) external;
function getTokenPrice(address token) external view returns (Internal.TimestampedUint192Value memory);
function getValidatedTokenPrice(address token) external view returns (uint192);
function getTokenPrices(address[] calldata tokens) external view returns (Internal.TimestampedUint192Value[] memory);
function getDestinationChainGasPrice(
uint64 destChainSelector
) external view returns (Internal.TimestampedUint192Value memory);
function getTokenAndGasPrices(
address token,
uint64 destChainSelector
) external view returns (uint192 tokenPrice, uint192 gasPrice);
function convertTokenAmount(
address fromToken,
uint256 fromTokenAmount,
address toToken
) external view returns (uint256 toTokenAmount);
}
文件 6 的 11:Internal.sol
pragma solidity ^0.8.0;
import {Client} from "./Client.sol";
import {MerkleMultiProof} from "../libraries/MerkleMultiProof.sol";
library Internal {
struct PriceUpdates {
TokenPriceUpdate[] tokenPriceUpdates;
uint64 destChainSelector;
uint192 usdPerUnitGas;
}
struct TokenPriceUpdate {
address sourceToken;
uint192 usdPerToken;
}
struct TimestampedUint192Value {
uint192 value;
uint64 timestamp;
}
struct PoolUpdate {
address token;
address pool;
}
struct ExecutionReport {
EVM2EVMMessage[] messages;
bytes[][] offchainTokenData;
bytes32[] proofs;
uint256 proofFlagBits;
}
struct EVM2EVMMessage {
uint64 sourceChainSelector;
uint64 sequenceNumber;
uint256 feeTokenAmount;
address sender;
uint64 nonce;
uint256 gasLimit;
bool strict;
address receiver;
bytes data;
Client.EVMTokenAmount[] tokenAmounts;
address feeToken;
bytes32 messageId;
}
function _toAny2EVMMessage(
EVM2EVMMessage memory original,
Client.EVMTokenAmount[] memory destTokenAmounts
) internal pure returns (Client.Any2EVMMessage memory message) {
message = Client.Any2EVMMessage({
messageId: original.messageId,
sourceChainSelector: original.sourceChainSelector,
sender: abi.encode(original.sender),
data: original.data,
destTokenAmounts: destTokenAmounts
});
}
bytes32 internal constant EVM_2_EVM_MESSAGE_HASH = keccak256("EVM2EVMMessageEvent");
function _hash(EVM2EVMMessage memory original, bytes32 metadataHash) internal pure returns (bytes32) {
return
keccak256(
abi.encode(
MerkleMultiProof.LEAF_DOMAIN_SEPARATOR,
metadataHash,
original.sequenceNumber,
original.nonce,
original.sender,
original.receiver,
keccak256(original.data),
keccak256(abi.encode(original.tokenAmounts)),
original.gasLimit,
original.strict,
original.feeToken,
original.feeTokenAmount
)
);
}
enum MessageExecutionState {
UNTOUCHED,
IN_PROGRESS,
SUCCESS,
FAILURE
}
}
文件 7 的 11:MerkleMultiProof.sol
pragma solidity ^0.8.0;
library MerkleMultiProof {
bytes32 internal constant LEAF_DOMAIN_SEPARATOR = 0x0000000000000000000000000000000000000000000000000000000000000000;
bytes32 internal constant INTERNAL_DOMAIN_SEPARATOR =
0x0000000000000000000000000000000000000000000000000000000000000001;
uint256 internal constant MAX_NUM_HASHES = 256;
error InvalidProof();
error LeavesCannotBeEmpty();
function merkleRoot(
bytes32[] memory leaves,
bytes32[] memory proofs,
uint256 proofFlagBits
) internal pure returns (bytes32) {
unchecked {
uint256 leavesLen = leaves.length;
uint256 proofsLen = proofs.length;
if (leavesLen == 0) revert LeavesCannotBeEmpty();
if (!(leavesLen <= MAX_NUM_HASHES + 1 && proofsLen <= MAX_NUM_HASHES + 1)) revert InvalidProof();
uint256 totalHashes = leavesLen + proofsLen - 1;
if (!(totalHashes <= MAX_NUM_HASHES)) revert InvalidProof();
if (totalHashes == 0) {
return leaves[0];
}
bytes32[] memory hashes = new bytes32[](totalHashes);
(uint256 leafPos, uint256 hashPos, uint256 proofPos) = (0, 0, 0);
for (uint256 i = 0; i < totalHashes; ++i) {
bytes32 a;
if (proofFlagBits & (1 << i) == (1 << i)) {
if (leafPos < leavesLen) {
a = leaves[leafPos++];
} else {
a = hashes[hashPos++];
}
} else {
a = proofs[proofPos++];
}
bytes32 b;
if (leafPos < leavesLen) {
b = leaves[leafPos++];
} else {
b = hashes[hashPos++];
}
if (!(hashPos <= i)) revert InvalidProof();
hashes[i] = _hashPair(a, b);
}
if (!(hashPos == totalHashes - 1 && leafPos == leavesLen && proofPos == proofsLen)) revert InvalidProof();
return hashes[totalHashes - 1];
}
}
function _hashInternalNode(bytes32 left, bytes32 right) private pure returns (bytes32 hash) {
return keccak256(abi.encode(INTERNAL_DOMAIN_SEPARATOR, left, right));
}
function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
return a < b ? _hashInternalNode(a, b) : _hashInternalNode(b, a);
}
}
文件 8 的 11:OwnableInterface.sol
pragma solidity ^0.8.0;
interface OwnableInterface {
function owner() external returns (address);
function transferOwnership(address recipient) external;
function acceptOwnership() external;
}
文件 9 的 11:OwnerIsCreator.sol
pragma solidity ^0.8.0;
import {ConfirmedOwner} from "../../ConfirmedOwner.sol";
contract OwnerIsCreator is ConfirmedOwner {
constructor() ConfirmedOwner(msg.sender) {}
}
文件 10 的 11:PriceRegistry.sol
pragma solidity 0.8.19;
import {IPriceRegistry} from "./interfaces/IPriceRegistry.sol";
import {OwnerIsCreator} from "./../shared/access/OwnerIsCreator.sol";
import {Internal} from "./libraries/Internal.sol";
import {USDPriceWith18Decimals} from "./libraries/USDPriceWith18Decimals.sol";
import {EnumerableSet} from "../vendor/openzeppelin-solidity/v4.8.0/utils/structs/EnumerableSet.sol";
contract PriceRegistry is IPriceRegistry, OwnerIsCreator {
using EnumerableSet for EnumerableSet.AddressSet;
using USDPriceWith18Decimals for uint192;
error TokenNotSupported(address token);
error ChainNotSupported(uint64 chain);
error OnlyCallableByUpdaterOrOwner();
error StaleGasPrice(uint64 destChainSelector, uint256 threshold, uint256 timePassed);
error StaleTokenPrice(address token, uint256 threshold, uint256 timePassed);
error InvalidStalenessThreshold();
event PriceUpdaterSet(address indexed priceUpdater);
event PriceUpdaterRemoved(address indexed priceUpdater);
event FeeTokenAdded(address indexed feeToken);
event FeeTokenRemoved(address indexed feeToken);
event UsdPerUnitGasUpdated(uint64 indexed destChain, uint256 value, uint256 timestamp);
event UsdPerTokenUpdated(address indexed token, uint256 value, uint256 timestamp);
mapping(uint64 destChainSelector => Internal.TimestampedUint192Value price)
private s_usdPerUnitGasByDestChainSelector;
mapping(address token => Internal.TimestampedUint192Value price) private s_usdPerToken;
EnumerableSet.AddressSet private s_priceUpdaters;
EnumerableSet.AddressSet private s_feeTokens;
uint32 private immutable i_stalenessThreshold;
constructor(address[] memory priceUpdaters, address[] memory feeTokens, uint32 stalenessThreshold) {
_applyPriceUpdatersUpdates(priceUpdaters, new address[](0));
_applyFeeTokensUpdates(feeTokens, new address[](0));
if (stalenessThreshold == 0) revert InvalidStalenessThreshold();
i_stalenessThreshold = stalenessThreshold;
}
function getTokenPrice(address token) public view override returns (Internal.TimestampedUint192Value memory) {
return s_usdPerToken[token];
}
function getValidatedTokenPrice(address token) external view override returns (uint192) {
return _getValidatedTokenPrice(token);
}
function getTokenPrices(
address[] calldata tokens
) external view override returns (Internal.TimestampedUint192Value[] memory) {
uint256 length = tokens.length;
Internal.TimestampedUint192Value[] memory tokenPrices = new Internal.TimestampedUint192Value[](length);
for (uint256 i = 0; i < length; ++i) {
tokenPrices[i] = getTokenPrice(tokens[i]);
}
return tokenPrices;
}
function getStalenessThreshold() external view returns (uint128) {
return i_stalenessThreshold;
}
function getDestinationChainGasPrice(
uint64 destChainSelector
) external view override returns (Internal.TimestampedUint192Value memory) {
return s_usdPerUnitGasByDestChainSelector[destChainSelector];
}
function getTokenAndGasPrices(
address token,
uint64 destChainSelector
) external view override returns (uint192 tokenPrice, uint192 gasPriceValue) {
Internal.TimestampedUint192Value memory gasPrice = s_usdPerUnitGasByDestChainSelector[destChainSelector];
if (gasPrice.timestamp == 0) revert ChainNotSupported(destChainSelector);
uint256 timePassed = block.timestamp - gasPrice.timestamp;
if (timePassed > i_stalenessThreshold) revert StaleGasPrice(destChainSelector, i_stalenessThreshold, timePassed);
return (_getValidatedTokenPrice(token), gasPrice.value);
}
function convertTokenAmount(
address fromToken,
uint256 fromTokenAmount,
address toToken
) external view override returns (uint256) {
return (fromTokenAmount * _getValidatedTokenPrice(fromToken)) / _getValidatedTokenPrice(toToken);
}
function _getValidatedTokenPrice(address token) internal view returns (uint192) {
Internal.TimestampedUint192Value memory tokenPrice = s_usdPerToken[token];
if (tokenPrice.timestamp == 0 || tokenPrice.value == 0) revert TokenNotSupported(token);
uint256 timePassed = block.timestamp - tokenPrice.timestamp;
if (timePassed > i_stalenessThreshold) revert StaleTokenPrice(token, i_stalenessThreshold, timePassed);
return tokenPrice.value;
}
function getFeeTokens() external view returns (address[] memory) {
return s_feeTokens.values();
}
function applyFeeTokensUpdates(
address[] memory feeTokensToAdd,
address[] memory feeTokensToRemove
) external onlyOwner {
_applyFeeTokensUpdates(feeTokensToAdd, feeTokensToRemove);
}
function _applyFeeTokensUpdates(address[] memory feeTokensToAdd, address[] memory feeTokensToRemove) private {
for (uint256 i = 0; i < feeTokensToAdd.length; ++i) {
if (s_feeTokens.add(feeTokensToAdd[i])) {
emit FeeTokenAdded(feeTokensToAdd[i]);
}
}
for (uint256 i = 0; i < feeTokensToRemove.length; ++i) {
if (s_feeTokens.remove(feeTokensToRemove[i])) {
emit FeeTokenRemoved(feeTokensToRemove[i]);
}
}
}
function updatePrices(Internal.PriceUpdates calldata priceUpdates) external override requireUpdaterOrOwner {
uint256 priceUpdatesLength = priceUpdates.tokenPriceUpdates.length;
for (uint256 i = 0; i < priceUpdatesLength; ++i) {
Internal.TokenPriceUpdate memory update = priceUpdates.tokenPriceUpdates[i];
s_usdPerToken[update.sourceToken] = Internal.TimestampedUint192Value({
value: update.usdPerToken,
timestamp: uint64(block.timestamp)
});
emit UsdPerTokenUpdated(update.sourceToken, update.usdPerToken, block.timestamp);
}
if (priceUpdates.destChainSelector != 0) {
s_usdPerUnitGasByDestChainSelector[priceUpdates.destChainSelector] = Internal.TimestampedUint192Value({
value: priceUpdates.usdPerUnitGas,
timestamp: uint64(block.timestamp)
});
emit UsdPerUnitGasUpdated(priceUpdates.destChainSelector, priceUpdates.usdPerUnitGas, block.timestamp);
}
}
function getPriceUpdaters() external view returns (address[] memory) {
return s_priceUpdaters.values();
}
function applyPriceUpdatersUpdates(
address[] memory priceUpdatersToAdd,
address[] memory priceUpdatersToRemove
) external onlyOwner {
_applyPriceUpdatersUpdates(priceUpdatersToAdd, priceUpdatersToRemove);
}
function _applyPriceUpdatersUpdates(
address[] memory priceUpdatersToAdd,
address[] memory priceUpdatersToRemove
) private {
for (uint256 i = 0; i < priceUpdatersToAdd.length; ++i) {
if (s_priceUpdaters.add(priceUpdatersToAdd[i])) {
emit PriceUpdaterSet(priceUpdatersToAdd[i]);
}
}
for (uint256 i = 0; i < priceUpdatersToRemove.length; ++i) {
if (s_priceUpdaters.remove(priceUpdatersToRemove[i])) {
emit PriceUpdaterRemoved(priceUpdatersToRemove[i]);
}
}
}
modifier requireUpdaterOrOwner() {
if (msg.sender != owner() && !s_priceUpdaters.contains(msg.sender)) revert OnlyCallableByUpdaterOrOwner();
_;
}
}
文件 11 的 11:USDPriceWith18Decimals.sol
pragma solidity ^0.8.0;
library USDPriceWith18Decimals {
function _calcUSDValueFromTokenAmount(uint192 tokenPrice, uint256 tokenAmount) internal pure returns (uint256) {
return (tokenPrice * tokenAmount) / 1e18;
}
function _calcTokenAmountFromUSDValue(uint192 tokenPrice, uint256 usdValue) internal pure returns (uint256) {
return (usdValue * 1e18) / tokenPrice;
}
}
{
"compilationTarget": {
"src/v0.8/ccip/PriceRegistry.sol": "PriceRegistry"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "none"
},
"optimizer": {
"enabled": true,
"runs": 26000
},
"remappings": [
":@eth-optimism/=node_modules/@eth-optimism/",
":@openzeppelin/=node_modules/@openzeppelin/",
":ds-test/=foundry-lib/forge-std/lib/ds-test/src/",
":erc4626-tests/=foundry-lib/openzeppelin-contracts/lib/erc4626-tests/",
":forge-std/=foundry-lib/forge-std/src/",
":hardhat/=node_modules/hardhat/",
":openzeppelin-contracts/=foundry-lib/openzeppelin-contracts/contracts/"
]
}
[{"inputs":[{"internalType":"address[]","name":"priceUpdaters","type":"address[]"},{"internalType":"address[]","name":"feeTokens","type":"address[]"},{"internalType":"uint32","name":"stalenessThreshold","type":"uint32"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint64","name":"chain","type":"uint64"}],"name":"ChainNotSupported","type":"error"},{"inputs":[],"name":"InvalidStalenessThreshold","type":"error"},{"inputs":[],"name":"OnlyCallableByUpdaterOrOwner","type":"error"},{"inputs":[{"internalType":"uint64","name":"destChainSelector","type":"uint64"},{"internalType":"uint256","name":"threshold","type":"uint256"},{"internalType":"uint256","name":"timePassed","type":"uint256"}],"name":"StaleGasPrice","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"threshold","type":"uint256"},{"internalType":"uint256","name":"timePassed","type":"uint256"}],"name":"StaleTokenPrice","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"TokenNotSupported","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"feeToken","type":"address"}],"name":"FeeTokenAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"feeToken","type":"address"}],"name":"FeeTokenRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"priceUpdater","type":"address"}],"name":"PriceUpdaterRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"priceUpdater","type":"address"}],"name":"PriceUpdaterSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"UsdPerTokenUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"destChain","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"UsdPerUnitGasUpdated","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"feeTokensToAdd","type":"address[]"},{"internalType":"address[]","name":"feeTokensToRemove","type":"address[]"}],"name":"applyFeeTokensUpdates","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"priceUpdatersToAdd","type":"address[]"},{"internalType":"address[]","name":"priceUpdatersToRemove","type":"address[]"}],"name":"applyPriceUpdatersUpdates","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"fromToken","type":"address"},{"internalType":"uint256","name":"fromTokenAmount","type":"uint256"},{"internalType":"address","name":"toToken","type":"address"}],"name":"convertTokenAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"destChainSelector","type":"uint64"}],"name":"getDestinationChainGasPrice","outputs":[{"components":[{"internalType":"uint192","name":"value","type":"uint192"},{"internalType":"uint64","name":"timestamp","type":"uint64"}],"internalType":"struct Internal.TimestampedUint192Value","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFeeTokens","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPriceUpdaters","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStalenessThreshold","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint64","name":"destChainSelector","type":"uint64"}],"name":"getTokenAndGasPrices","outputs":[{"internalType":"uint192","name":"tokenPrice","type":"uint192"},{"internalType":"uint192","name":"gasPriceValue","type":"uint192"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getTokenPrice","outputs":[{"components":[{"internalType":"uint192","name":"value","type":"uint192"},{"internalType":"uint64","name":"timestamp","type":"uint64"}],"internalType":"struct Internal.TimestampedUint192Value","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"}],"name":"getTokenPrices","outputs":[{"components":[{"internalType":"uint192","name":"value","type":"uint192"},{"internalType":"uint64","name":"timestamp","type":"uint64"}],"internalType":"struct Internal.TimestampedUint192Value[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getValidatedTokenPrice","outputs":[{"internalType":"uint192","name":"","type":"uint192"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"sourceToken","type":"address"},{"internalType":"uint192","name":"usdPerToken","type":"uint192"}],"internalType":"struct Internal.TokenPriceUpdate[]","name":"tokenPriceUpdates","type":"tuple[]"},{"internalType":"uint64","name":"destChainSelector","type":"uint64"},{"internalType":"uint192","name":"usdPerUnitGas","type":"uint192"}],"internalType":"struct Internal.PriceUpdates","name":"priceUpdates","type":"tuple"}],"name":"updatePrices","outputs":[],"stateMutability":"nonpayable","type":"function"}]