编译器
0.8.19+commit.7dd6d404
文件 1 的 25:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
文件 2 的 25:AggregateRateLimiter.sol
pragma solidity 0.8.19;
import {IPriceRegistry} from "./interfaces/IPriceRegistry.sol";
import {OwnerIsCreator} from "./../shared/access/OwnerIsCreator.sol";
import {Client} from "./libraries/Client.sol";
import {RateLimiter} from "./libraries/RateLimiter.sol";
import {USDPriceWith18Decimals} from "./libraries/USDPriceWith18Decimals.sol";
contract AggregateRateLimiter is OwnerIsCreator {
using RateLimiter for RateLimiter.TokenBucket;
using USDPriceWith18Decimals for uint224;
error PriceNotFoundForToken(address token);
event AdminSet(address newAdmin);
address internal s_admin;
RateLimiter.TokenBucket private s_rateLimiter;
constructor(RateLimiter.Config memory config) {
s_rateLimiter = RateLimiter.TokenBucket({
rate: config.rate,
capacity: config.capacity,
tokens: config.capacity,
lastUpdated: uint32(block.timestamp),
isEnabled: config.isEnabled
});
}
function _rateLimitValue(Client.EVMTokenAmount[] memory tokenAmounts, IPriceRegistry priceRegistry) internal {
uint256 numberOfTokens = tokenAmounts.length;
uint256 value = 0;
for (uint256 i = 0; i < numberOfTokens; ++i) {
uint224 pricePerToken = priceRegistry.getTokenPrice(tokenAmounts[i].token).value;
if (pricePerToken == 0) revert PriceNotFoundForToken(tokenAmounts[i].token);
value += pricePerToken._calcUSDValueFromTokenAmount(tokenAmounts[i].amount);
}
s_rateLimiter._consume(value, address(0));
}
function currentRateLimiterState() external view returns (RateLimiter.TokenBucket memory) {
return s_rateLimiter._currentTokenBucketState();
}
function setRateLimiterConfig(RateLimiter.Config memory config) external onlyAdminOrOwner {
s_rateLimiter._setTokenBucketConfig(config);
}
function getTokenLimitAdmin() external view returns (address) {
return s_admin;
}
function setAdmin(address newAdmin) external onlyAdminOrOwner {
s_admin = newAdmin;
emit AdminSet(newAdmin);
}
modifier onlyAdminOrOwner() {
if (msg.sender != owner() && msg.sender != s_admin) revert RateLimiter.OnlyCallableByAdminOrOwner();
_;
}
}
文件 3 的 25: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;
}
function _argsToBytes(EVMExtraArgsV1 memory extraArgs) internal pure returns (bytes memory bts) {
return abi.encodeWithSelector(EVM_EXTRA_ARGS_V1_TAG, extraArgs);
}
}
文件 4 的 25:ConfirmedOwner.sol
pragma solidity ^0.8.0;
import {ConfirmedOwnerWithProposal} from "./ConfirmedOwnerWithProposal.sol";
contract ConfirmedOwner is ConfirmedOwnerWithProposal {
constructor(address newOwner) ConfirmedOwnerWithProposal(newOwner, address(0)) {}
}
文件 5 的 25:ConfirmedOwnerWithProposal.sol
pragma solidity ^0.8.0;
import {IOwnable} from "../interfaces/IOwnable.sol";
contract ConfirmedOwnerWithProposal is IOwnable {
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();
_;
}
}
文件 6 的 25:EVM2EVMOnRamp.sol
pragma solidity 0.8.19;
import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol";
import {IPool} from "../interfaces/pools/IPool.sol";
import {IARM} from "../interfaces/IARM.sol";
import {IPriceRegistry} from "../interfaces/IPriceRegistry.sol";
import {IEVM2AnyOnRamp} from "../interfaces/IEVM2AnyOnRamp.sol";
import {IEVM2AnyOnRampClient} from "../interfaces/IEVM2AnyOnRampClient.sol";
import {ILinkAvailable} from "../interfaces/automation/ILinkAvailable.sol";
import {AggregateRateLimiter} from "../AggregateRateLimiter.sol";
import {Client} from "../libraries/Client.sol";
import {Internal} from "../libraries/Internal.sol";
import {RateLimiter} from "../libraries/RateLimiter.sol";
import {USDPriceWith18Decimals} from "../libraries/USDPriceWith18Decimals.sol";
import {EnumerableMapAddresses} from "../../shared/enumerable/EnumerableMapAddresses.sol";
import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol";
import {EnumerableMap} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableMap.sol";
contract EVM2EVMOnRamp is IEVM2AnyOnRamp, ILinkAvailable, AggregateRateLimiter, ITypeAndVersion {
using SafeERC20 for IERC20;
using EnumerableMap for EnumerableMap.AddressToUintMap;
using EnumerableMapAddresses for EnumerableMapAddresses.AddressToAddressMap;
using USDPriceWith18Decimals for uint224;
error InvalidExtraArgsTag();
error OnlyCallableByOwnerOrAdmin();
error OnlyCallableByOwnerOrAdminOrNop();
error InvalidWithdrawParams();
error NoFeesToPay();
error NoNopsToPay();
error InsufficientBalance();
error TooManyNops();
error MaxFeeBalanceReached();
error MessageTooLarge(uint256 maxSize, uint256 actualSize);
error MessageGasLimitTooHigh();
error UnsupportedNumberOfTokens();
error UnsupportedToken(IERC20 token);
error MustBeCalledByRouter();
error RouterMustSetOriginalSender();
error InvalidTokenPoolConfig();
error PoolAlreadyAdded();
error PoolDoesNotExist(address token);
error TokenPoolMismatch();
error InvalidConfig();
error InvalidAddress(bytes encodedAddress);
error BadARMSignal();
error LinkBalanceNotSettled();
error InvalidNopAddress(address nop);
error NotAFeeToken(address token);
error CannotSendZeroTokens();
error SourceTokenDataTooLarge(address token);
error InvalidChainSelector(uint64 chainSelector);
event ConfigSet(StaticConfig staticConfig, DynamicConfig dynamicConfig);
event NopPaid(address indexed nop, uint256 amount);
event FeeConfigSet(FeeTokenConfigArgs[] feeConfig);
event TokenTransferFeeConfigSet(TokenTransferFeeConfigArgs[] transferFeeConfig);
event CCIPSendRequested(Internal.EVM2EVMMessage message);
event NopsSet(uint256 nopWeightsTotal, NopAndWeight[] nopsAndWeights);
event PoolAdded(address token, address pool);
event PoolRemoved(address token, address pool);
struct StaticConfig {
address linkToken;
uint64 chainSelector;
uint64 destChainSelector;
uint64 defaultTxGasLimit;
uint96 maxNopFeesJuels;
address prevOnRamp;
address armProxy;
}
struct DynamicConfig {
address router;
uint16 maxNumberOfTokensPerMsg;
uint32 destGasOverhead;
uint16 destGasPerPayloadByte;
uint32 destDataAvailabilityOverheadGas;
uint16 destGasPerDataAvailabilityByte;
uint16 destDataAvailabilityMultiplierBps;
address priceRegistry;
uint32 maxDataBytes;
uint32 maxPerMsgGasLimit;
}
struct FeeTokenConfig {
uint32 networkFeeUSDCents;
uint64 gasMultiplierWeiPerEth;
uint64 premiumMultiplierWeiPerEth;
bool enabled;
}
struct FeeTokenConfigArgs {
address token;
uint32 networkFeeUSDCents;
uint64 gasMultiplierWeiPerEth;
uint64 premiumMultiplierWeiPerEth;
bool enabled;
}
struct TokenTransferFeeConfig {
uint32 minFeeUSDCents;
uint32 maxFeeUSDCents;
uint16 deciBps;
uint32 destGasOverhead;
uint32 destBytesOverhead;
}
struct TokenTransferFeeConfigArgs {
address token;
uint32 minFeeUSDCents;
uint32 maxFeeUSDCents;
uint16 deciBps;
uint32 destGasOverhead;
uint32 destBytesOverhead;
}
struct NopAndWeight {
address nop;
uint16 weight;
}
string public constant override typeAndVersion = "EVM2EVMOnRamp 1.2.0";
bytes32 internal immutable i_metadataHash;
uint64 internal immutable i_defaultTxGasLimit;
uint96 internal immutable i_maxNopFeesJuels;
address internal immutable i_linkToken;
uint64 internal immutable i_chainSelector;
uint64 internal immutable i_destChainSelector;
address internal immutable i_prevOnRamp;
address internal immutable i_armProxy;
uint256 private constant MAX_NUMBER_OF_NOPS = 64;
DynamicConfig internal s_dynamicConfig;
EnumerableMap.AddressToUintMap internal s_nops;
EnumerableMapAddresses.AddressToAddressMap private s_poolsBySourceToken;
mapping(address token => FeeTokenConfig feeTokenConfig) internal s_feeTokenConfig;
mapping(address token => TokenTransferFeeConfig tranferFeeConfig) internal s_tokenTransferFeeConfig;
mapping(address sender => uint64 nonce) internal s_senderNonce;
uint96 internal s_nopFeesJuels;
uint32 internal s_nopWeightsTotal;
uint64 internal s_sequenceNumber;
constructor(
StaticConfig memory staticConfig,
DynamicConfig memory dynamicConfig,
Internal.PoolUpdate[] memory tokensAndPools,
RateLimiter.Config memory rateLimiterConfig,
FeeTokenConfigArgs[] memory feeTokenConfigs,
TokenTransferFeeConfigArgs[] memory tokenTransferFeeConfigArgs,
NopAndWeight[] memory nopsAndWeights
) AggregateRateLimiter(rateLimiterConfig) {
if (
staticConfig.linkToken == address(0) ||
staticConfig.chainSelector == 0 ||
staticConfig.destChainSelector == 0 ||
staticConfig.defaultTxGasLimit == 0 ||
staticConfig.armProxy == address(0)
) revert InvalidConfig();
i_metadataHash = keccak256(
abi.encode(
Internal.EVM_2_EVM_MESSAGE_HASH,
staticConfig.chainSelector,
staticConfig.destChainSelector,
address(this)
)
);
i_linkToken = staticConfig.linkToken;
i_chainSelector = staticConfig.chainSelector;
i_destChainSelector = staticConfig.destChainSelector;
i_defaultTxGasLimit = staticConfig.defaultTxGasLimit;
i_maxNopFeesJuels = staticConfig.maxNopFeesJuels;
i_prevOnRamp = staticConfig.prevOnRamp;
i_armProxy = staticConfig.armProxy;
_setDynamicConfig(dynamicConfig);
_setFeeTokenConfig(feeTokenConfigs);
_setTokenTransferFeeConfig(tokenTransferFeeConfigArgs);
_setNops(nopsAndWeights);
_applyPoolUpdates(new Internal.PoolUpdate[](0), tokensAndPools);
}
function getExpectedNextSequenceNumber() external view returns (uint64) {
return s_sequenceNumber + 1;
}
function getSenderNonce(address sender) external view returns (uint64) {
uint256 senderNonce = s_senderNonce[sender];
if (senderNonce == 0 && i_prevOnRamp != address(0)) {
return IEVM2AnyOnRamp(i_prevOnRamp).getSenderNonce(sender);
}
return uint64(senderNonce);
}
function forwardFromRouter(
uint64 destChainSelector,
Client.EVM2AnyMessage calldata message,
uint256 feeTokenAmount,
address originalSender
) external whenHealthy returns (bytes32) {
if (originalSender == address(0)) revert RouterMustSetOriginalSender();
if (msg.sender != s_dynamicConfig.router) revert MustBeCalledByRouter();
if (destChainSelector != i_destChainSelector) revert InvalidChainSelector(destChainSelector);
if (message.receiver.length != 32) revert InvalidAddress(message.receiver);
uint256 decodedReceiver = abi.decode(message.receiver, (uint256));
if (decodedReceiver > type(uint160).max || decodedReceiver < 10) revert InvalidAddress(message.receiver);
uint256 gasLimit = _fromBytes(message.extraArgs).gasLimit;
uint256 numberOfTokens = message.tokenAmounts.length;
_validateMessage(message.data.length, gasLimit, numberOfTokens);
if (numberOfTokens > 0) {
for (uint256 i = 0; i < numberOfTokens; ++i) {
if (message.tokenAmounts[i].amount == 0) revert CannotSendZeroTokens();
}
_rateLimitValue(message.tokenAmounts, IPriceRegistry(s_dynamicConfig.priceRegistry));
}
if (message.feeToken == i_linkToken) {
s_nopFeesJuels += uint96(feeTokenAmount);
} else {
s_nopFeesJuels += uint96(
IPriceRegistry(s_dynamicConfig.priceRegistry).convertTokenAmount(message.feeToken, feeTokenAmount, i_linkToken)
);
}
if (s_nopFeesJuels > i_maxNopFeesJuels) revert MaxFeeBalanceReached();
if (s_senderNonce[originalSender] == 0 && i_prevOnRamp != address(0)) {
s_senderNonce[originalSender] = IEVM2AnyOnRamp(i_prevOnRamp).getSenderNonce(originalSender);
}
Internal.EVM2EVMMessage memory newMessage = Internal.EVM2EVMMessage({
sourceChainSelector: i_chainSelector,
sender: originalSender,
receiver: address(uint160(decodedReceiver)),
sequenceNumber: ++s_sequenceNumber,
gasLimit: gasLimit,
strict: false,
nonce: ++s_senderNonce[originalSender],
feeToken: message.feeToken,
feeTokenAmount: feeTokenAmount,
data: message.data,
tokenAmounts: message.tokenAmounts,
sourceTokenData: new bytes[](numberOfTokens),
messageId: ""
});
for (uint256 i = 0; i < numberOfTokens; ++i) {
Client.EVMTokenAmount memory tokenAndAmount = message.tokenAmounts[i];
bytes memory tokenData = getPoolBySourceToken(destChainSelector, IERC20(tokenAndAmount.token)).lockOrBurn(
originalSender,
message.receiver,
tokenAndAmount.amount,
i_destChainSelector,
bytes("")
);
if (tokenData.length > s_tokenTransferFeeConfig[tokenAndAmount.token].destBytesOverhead)
revert SourceTokenDataTooLarge(tokenAndAmount.token);
newMessage.sourceTokenData[i] = tokenData;
}
newMessage.messageId = Internal._hash(newMessage, i_metadataHash);
emit CCIPSendRequested(newMessage);
return newMessage.messageId;
}
function _fromBytes(bytes calldata extraArgs) internal view returns (Client.EVMExtraArgsV1 memory) {
if (extraArgs.length == 0) {
return Client.EVMExtraArgsV1({gasLimit: i_defaultTxGasLimit});
}
if (bytes4(extraArgs) != Client.EVM_EXTRA_ARGS_V1_TAG) revert InvalidExtraArgsTag();
return abi.decode(extraArgs[4:], (Client.EVMExtraArgsV1));
}
function _validateMessage(uint256 dataLength, uint256 gasLimit, uint256 numberOfTokens) internal view {
uint256 maxDataBytes = uint256(s_dynamicConfig.maxDataBytes);
if (dataLength > maxDataBytes) revert MessageTooLarge(maxDataBytes, dataLength);
if (gasLimit > uint256(s_dynamicConfig.maxPerMsgGasLimit)) revert MessageGasLimitTooHigh();
if (numberOfTokens > uint256(s_dynamicConfig.maxNumberOfTokensPerMsg)) revert UnsupportedNumberOfTokens();
}
function getStaticConfig() external view returns (StaticConfig memory) {
return
StaticConfig({
linkToken: i_linkToken,
chainSelector: i_chainSelector,
destChainSelector: i_destChainSelector,
defaultTxGasLimit: i_defaultTxGasLimit,
maxNopFeesJuels: i_maxNopFeesJuels,
prevOnRamp: i_prevOnRamp,
armProxy: i_armProxy
});
}
function getDynamicConfig() external view returns (DynamicConfig memory dynamicConfig) {
return s_dynamicConfig;
}
function setDynamicConfig(DynamicConfig memory dynamicConfig) external onlyOwner {
_setDynamicConfig(dynamicConfig);
}
function _setDynamicConfig(DynamicConfig memory dynamicConfig) internal {
if (dynamicConfig.priceRegistry == address(0)) revert InvalidConfig();
s_dynamicConfig = dynamicConfig;
emit ConfigSet(
StaticConfig({
linkToken: i_linkToken,
chainSelector: i_chainSelector,
destChainSelector: i_destChainSelector,
defaultTxGasLimit: i_defaultTxGasLimit,
maxNopFeesJuels: i_maxNopFeesJuels,
prevOnRamp: i_prevOnRamp,
armProxy: i_armProxy
}),
dynamicConfig
);
}
function getSupportedTokens(uint64 ) external view returns (address[] memory) {
address[] memory sourceTokens = new address[](s_poolsBySourceToken.length());
for (uint256 i = 0; i < sourceTokens.length; ++i) {
(sourceTokens[i], ) = s_poolsBySourceToken.at(i);
}
return sourceTokens;
}
function getPoolBySourceToken(uint64 , IERC20 sourceToken) public view returns (IPool) {
if (!s_poolsBySourceToken.contains(address(sourceToken))) revert UnsupportedToken(sourceToken);
return IPool(s_poolsBySourceToken.get(address(sourceToken)));
}
function applyPoolUpdates(
Internal.PoolUpdate[] memory removes,
Internal.PoolUpdate[] memory adds
) external onlyOwner {
_applyPoolUpdates(removes, adds);
}
function _applyPoolUpdates(Internal.PoolUpdate[] memory removes, Internal.PoolUpdate[] memory adds) internal {
for (uint256 i = 0; i < removes.length; ++i) {
address token = removes[i].token;
address pool = removes[i].pool;
if (!s_poolsBySourceToken.contains(token)) revert PoolDoesNotExist(token);
if (s_poolsBySourceToken.get(token) != pool) revert TokenPoolMismatch();
if (s_poolsBySourceToken.remove(token)) {
emit PoolRemoved(token, pool);
}
}
for (uint256 i = 0; i < adds.length; ++i) {
address token = adds[i].token;
address pool = adds[i].pool;
if (token == address(0) || pool == address(0)) revert InvalidTokenPoolConfig();
if (token != address(IPool(pool).getToken())) revert TokenPoolMismatch();
if (s_poolsBySourceToken.set(token, pool)) {
emit PoolAdded(token, pool);
} else {
revert PoolAlreadyAdded();
}
}
}
function getFee(
uint64 destChainSelector,
Client.EVM2AnyMessage calldata message
) external view returns (uint256 feeTokenAmount) {
if (destChainSelector != i_destChainSelector) revert InvalidChainSelector(destChainSelector);
uint256 gasLimit = _fromBytes(message.extraArgs).gasLimit;
_validateMessage(message.data.length, gasLimit, message.tokenAmounts.length);
FeeTokenConfig memory feeTokenConfig = s_feeTokenConfig[message.feeToken];
if (!feeTokenConfig.enabled) revert NotAFeeToken(message.feeToken);
(uint224 feeTokenPrice, uint224 packedGasPrice) = IPriceRegistry(s_dynamicConfig.priceRegistry)
.getTokenAndGasPrices(message.feeToken, destChainSelector);
uint112 executionGasPrice = uint112(packedGasPrice);
uint256 premiumFee = 0;
uint32 tokenTransferGas = 0;
uint32 tokenTransferBytesOverhead = 0;
if (message.tokenAmounts.length > 0) {
(premiumFee, tokenTransferGas, tokenTransferBytesOverhead) = _getTokenTransferCost(
message.feeToken,
feeTokenPrice,
message.tokenAmounts
);
} else {
premiumFee = uint256(feeTokenConfig.networkFeeUSDCents) * 1e16;
}
premiumFee = premiumFee * feeTokenConfig.premiumMultiplierWeiPerEth;
uint256 executionCost = executionGasPrice *
((gasLimit +
s_dynamicConfig.destGasOverhead +
(message.data.length * s_dynamicConfig.destGasPerPayloadByte) +
tokenTransferGas) * feeTokenConfig.gasMultiplierWeiPerEth);
uint256 dataAvailabilityCost = 0;
if (s_dynamicConfig.destDataAvailabilityMultiplierBps > 0) {
uint112 dataAvailabilityGasPrice = uint112(packedGasPrice >> Internal.GAS_PRICE_BITS);
dataAvailabilityCost = _getDataAvailabilityCost(
dataAvailabilityGasPrice,
message.data.length,
message.tokenAmounts.length,
tokenTransferBytesOverhead
);
}
return (premiumFee + executionCost + dataAvailabilityCost) / feeTokenPrice;
}
function _getDataAvailabilityCost(
uint112 dataAvailabilityGasPrice,
uint256 messageDataLength,
uint256 numberOfTokens,
uint32 tokenTransferBytesOverhead
) internal view returns (uint256 dataAvailabilityCostUSD36Decimal) {
uint256 dataAvailabilityLengthBytes = Internal.MESSAGE_FIXED_BYTES +
messageDataLength +
(numberOfTokens * Internal.MESSAGE_FIXED_BYTES_PER_TOKEN) +
tokenTransferBytesOverhead;
uint256 dataAvailabilityGas = (dataAvailabilityLengthBytes * s_dynamicConfig.destGasPerDataAvailabilityByte) +
s_dynamicConfig.destDataAvailabilityOverheadGas;
return
((dataAvailabilityGas * dataAvailabilityGasPrice) * s_dynamicConfig.destDataAvailabilityMultiplierBps) * 1e14;
}
function _getTokenTransferCost(
address feeToken,
uint224 feeTokenPrice,
Client.EVMTokenAmount[] calldata tokenAmounts
) internal view returns (uint256 tokenTransferFeeUSDWei, uint32 tokenTransferGas, uint32 tokenTransferBytesOverhead) {
uint256 numberOfTokens = tokenAmounts.length;
for (uint256 i = 0; i < numberOfTokens; ++i) {
Client.EVMTokenAmount memory tokenAmount = tokenAmounts[i];
TokenTransferFeeConfig memory transferFeeConfig = s_tokenTransferFeeConfig[tokenAmount.token];
if (!s_poolsBySourceToken.contains(tokenAmount.token)) revert UnsupportedToken(IERC20(tokenAmount.token));
uint256 bpsFeeUSDWei = 0;
if (transferFeeConfig.deciBps > 0) {
uint224 tokenPrice = 0;
if (tokenAmount.token != feeToken) {
tokenPrice = IPriceRegistry(s_dynamicConfig.priceRegistry).getValidatedTokenPrice(tokenAmount.token);
} else {
tokenPrice = feeTokenPrice;
}
bpsFeeUSDWei = (tokenPrice._calcUSDValueFromTokenAmount(tokenAmount.amount) * transferFeeConfig.deciBps) / 1e5;
}
tokenTransferGas += transferFeeConfig.destGasOverhead;
tokenTransferBytesOverhead += transferFeeConfig.destBytesOverhead;
uint256 minFeeUSDWei = uint256(transferFeeConfig.minFeeUSDCents) * 1e16;
if (bpsFeeUSDWei < minFeeUSDWei) {
tokenTransferFeeUSDWei += minFeeUSDWei;
continue;
}
uint256 maxFeeUSDWei = uint256(transferFeeConfig.maxFeeUSDCents) * 1e16;
if (bpsFeeUSDWei > maxFeeUSDWei) {
tokenTransferFeeUSDWei += maxFeeUSDWei;
continue;
}
tokenTransferFeeUSDWei += bpsFeeUSDWei;
}
return (tokenTransferFeeUSDWei, tokenTransferGas, tokenTransferBytesOverhead);
}
function getFeeTokenConfig(address token) external view returns (FeeTokenConfig memory feeTokenConfig) {
return s_feeTokenConfig[token];
}
function setFeeTokenConfig(FeeTokenConfigArgs[] memory feeTokenConfigArgs) external onlyOwnerOrAdmin {
_setFeeTokenConfig(feeTokenConfigArgs);
}
function _setFeeTokenConfig(FeeTokenConfigArgs[] memory feeTokenConfigArgs) internal {
for (uint256 i = 0; i < feeTokenConfigArgs.length; ++i) {
FeeTokenConfigArgs memory configArg = feeTokenConfigArgs[i];
s_feeTokenConfig[configArg.token] = FeeTokenConfig({
networkFeeUSDCents: configArg.networkFeeUSDCents,
gasMultiplierWeiPerEth: configArg.gasMultiplierWeiPerEth,
premiumMultiplierWeiPerEth: configArg.premiumMultiplierWeiPerEth,
enabled: configArg.enabled
});
}
emit FeeConfigSet(feeTokenConfigArgs);
}
function getTokenTransferFeeConfig(
address token
) external view returns (TokenTransferFeeConfig memory tokenTransferFeeConfig) {
return s_tokenTransferFeeConfig[token];
}
function setTokenTransferFeeConfig(
TokenTransferFeeConfigArgs[] memory tokenTransferFeeConfigArgs
) external onlyOwnerOrAdmin {
_setTokenTransferFeeConfig(tokenTransferFeeConfigArgs);
}
function _setTokenTransferFeeConfig(TokenTransferFeeConfigArgs[] memory tokenTransferFeeConfigArgs) internal {
for (uint256 i = 0; i < tokenTransferFeeConfigArgs.length; ++i) {
TokenTransferFeeConfigArgs memory configArg = tokenTransferFeeConfigArgs[i];
s_tokenTransferFeeConfig[configArg.token] = TokenTransferFeeConfig({
minFeeUSDCents: configArg.minFeeUSDCents,
maxFeeUSDCents: configArg.maxFeeUSDCents,
deciBps: configArg.deciBps,
destGasOverhead: configArg.destGasOverhead,
destBytesOverhead: configArg.destBytesOverhead
});
}
emit TokenTransferFeeConfigSet(tokenTransferFeeConfigArgs);
}
function getNopFeesJuels() external view returns (uint96) {
return s_nopFeesJuels;
}
function getNops() external view returns (NopAndWeight[] memory nopsAndWeights, uint256 weightsTotal) {
uint256 length = s_nops.length();
nopsAndWeights = new NopAndWeight[](length);
for (uint256 i = 0; i < length; ++i) {
(address nopAddress, uint256 nopWeight) = s_nops.at(i);
nopsAndWeights[i] = NopAndWeight({nop: nopAddress, weight: uint16(nopWeight)});
}
weightsTotal = s_nopWeightsTotal;
return (nopsAndWeights, weightsTotal);
}
function setNops(NopAndWeight[] calldata nopsAndWeights) external onlyOwnerOrAdmin {
_setNops(nopsAndWeights);
}
function _setNops(NopAndWeight[] memory nopsAndWeights) internal {
uint256 numberOfNops = nopsAndWeights.length;
if (numberOfNops > MAX_NUMBER_OF_NOPS) revert TooManyNops();
if (s_nopWeightsTotal > 0 && s_nopFeesJuels >= s_nopWeightsTotal) {
payNops();
}
for (uint256 i = s_nops.length(); i > 0; --i) {
(address nop, ) = s_nops.at(i - 1);
s_nops.remove(nop);
}
uint32 nopWeightsTotal = 0;
for (uint256 i = 0; i < numberOfNops; ++i) {
address nop = nopsAndWeights[i].nop;
uint16 weight = nopsAndWeights[i].weight;
if (nop == i_linkToken || nop == address(0)) revert InvalidNopAddress(nop);
s_nops.set(nop, weight);
nopWeightsTotal += weight;
}
s_nopWeightsTotal = nopWeightsTotal;
emit NopsSet(nopWeightsTotal, nopsAndWeights);
}
function payNops() public onlyOwnerOrAdminOrNop {
uint256 weightsTotal = s_nopWeightsTotal;
if (weightsTotal == 0) revert NoNopsToPay();
uint96 totalFeesToPay = s_nopFeesJuels;
if (totalFeesToPay < weightsTotal) revert NoFeesToPay();
if (_linkLeftAfterNopFees() < 0) revert InsufficientBalance();
uint96 fundsLeft = totalFeesToPay;
uint256 numberOfNops = s_nops.length();
for (uint256 i = 0; i < numberOfNops; ++i) {
(address nop, uint256 weight) = s_nops.at(i);
uint96 amount = uint96((totalFeesToPay * weight) / weightsTotal);
fundsLeft -= amount;
IERC20(i_linkToken).safeTransfer(nop, amount);
emit NopPaid(nop, amount);
}
s_nopFeesJuels = fundsLeft;
}
function withdrawNonLinkFees(address feeToken, address to) external onlyOwnerOrAdmin {
if (feeToken == i_linkToken || to == address(0)) revert InvalidWithdrawParams();
if (_linkLeftAfterNopFees() < 0) revert LinkBalanceNotSettled();
IERC20(feeToken).safeTransfer(to, IERC20(feeToken).balanceOf(address(this)));
}
function _linkLeftAfterNopFees() private view returns (int256) {
return int256(IERC20(i_linkToken).balanceOf(address(this))) - int256(uint256(s_nopFeesJuels));
}
function linkAvailableForPayment() external view returns (int256) {
return _linkLeftAfterNopFees();
}
modifier onlyOwnerOrAdminOrNop() {
if (msg.sender != owner() && msg.sender != s_admin && !s_nops.contains(msg.sender))
revert OnlyCallableByOwnerOrAdminOrNop();
_;
}
modifier onlyOwnerOrAdmin() {
if (msg.sender != owner() && msg.sender != s_admin) revert OnlyCallableByOwnerOrAdmin();
_;
}
modifier whenHealthy() {
if (IARM(i_armProxy).isCursed()) revert BadARMSignal();
_;
}
}
文件 7 的 25:EnumerableMap.sol
pragma solidity ^0.8.0;
import "./EnumerableSet.sol";
library EnumerableMap {
using EnumerableSet for EnumerableSet.Bytes32Set;
struct Bytes32ToBytes32Map {
EnumerableSet.Bytes32Set _keys;
mapping(bytes32 => bytes32) _values;
}
function set(
Bytes32ToBytes32Map storage map,
bytes32 key,
bytes32 value
) internal returns (bool) {
map._values[key] = value;
return map._keys.add(key);
}
function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) {
delete map._values[key];
return map._keys.remove(key);
}
function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) {
return map._keys.contains(key);
}
function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) {
return map._keys.length();
}
function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32, bytes32) {
bytes32 key = map._keys.at(index);
return (key, map._values[key]);
}
function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) {
bytes32 value = map._values[key];
if (value == bytes32(0)) {
return (contains(map, key), bytes32(0));
} else {
return (true, value);
}
}
function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) {
bytes32 value = map._values[key];
require(value != 0 || contains(map, key), "EnumerableMap: nonexistent key");
return value;
}
function get(
Bytes32ToBytes32Map storage map,
bytes32 key,
string memory errorMessage
) internal view returns (bytes32) {
bytes32 value = map._values[key];
require(value != 0 || contains(map, key), errorMessage);
return value;
}
struct UintToUintMap {
Bytes32ToBytes32Map _inner;
}
function set(
UintToUintMap storage map,
uint256 key,
uint256 value
) internal returns (bool) {
return set(map._inner, bytes32(key), bytes32(value));
}
function remove(UintToUintMap storage map, uint256 key) internal returns (bool) {
return remove(map._inner, bytes32(key));
}
function contains(UintToUintMap storage map, uint256 key) internal view returns (bool) {
return contains(map._inner, bytes32(key));
}
function length(UintToUintMap storage map) internal view returns (uint256) {
return length(map._inner);
}
function at(UintToUintMap storage map, uint256 index) internal view returns (uint256, uint256) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (uint256(key), uint256(value));
}
function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool, uint256) {
(bool success, bytes32 value) = tryGet(map._inner, bytes32(key));
return (success, uint256(value));
}
function get(UintToUintMap storage map, uint256 key) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(key)));
}
function get(
UintToUintMap storage map,
uint256 key,
string memory errorMessage
) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(key), errorMessage));
}
struct UintToAddressMap {
Bytes32ToBytes32Map _inner;
}
function set(
UintToAddressMap storage map,
uint256 key,
address value
) internal returns (bool) {
return set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));
}
function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) {
return remove(map._inner, bytes32(key));
}
function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) {
return contains(map._inner, bytes32(key));
}
function length(UintToAddressMap storage map) internal view returns (uint256) {
return length(map._inner);
}
function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (uint256(key), address(uint160(uint256(value))));
}
function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) {
(bool success, bytes32 value) = tryGet(map._inner, bytes32(key));
return (success, address(uint160(uint256(value))));
}
function get(UintToAddressMap storage map, uint256 key) internal view returns (address) {
return address(uint160(uint256(get(map._inner, bytes32(key)))));
}
function get(
UintToAddressMap storage map,
uint256 key,
string memory errorMessage
) internal view returns (address) {
return address(uint160(uint256(get(map._inner, bytes32(key), errorMessage))));
}
struct AddressToUintMap {
Bytes32ToBytes32Map _inner;
}
function set(
AddressToUintMap storage map,
address key,
uint256 value
) internal returns (bool) {
return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value));
}
function remove(AddressToUintMap storage map, address key) internal returns (bool) {
return remove(map._inner, bytes32(uint256(uint160(key))));
}
function contains(AddressToUintMap storage map, address key) internal view returns (bool) {
return contains(map._inner, bytes32(uint256(uint160(key))));
}
function length(AddressToUintMap storage map) internal view returns (uint256) {
return length(map._inner);
}
function at(AddressToUintMap storage map, uint256 index) internal view returns (address, uint256) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (address(uint160(uint256(key))), uint256(value));
}
function tryGet(AddressToUintMap storage map, address key) internal view returns (bool, uint256) {
(bool success, bytes32 value) = tryGet(map._inner, bytes32(uint256(uint160(key))));
return (success, uint256(value));
}
function get(AddressToUintMap storage map, address key) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(uint256(uint160(key)))));
}
function get(
AddressToUintMap storage map,
address key,
string memory errorMessage
) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(uint256(uint160(key))), errorMessage));
}
struct Bytes32ToUintMap {
Bytes32ToBytes32Map _inner;
}
function set(
Bytes32ToUintMap storage map,
bytes32 key,
uint256 value
) internal returns (bool) {
return set(map._inner, key, bytes32(value));
}
function remove(Bytes32ToUintMap storage map, bytes32 key) internal returns (bool) {
return remove(map._inner, key);
}
function contains(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool) {
return contains(map._inner, key);
}
function length(Bytes32ToUintMap storage map) internal view returns (uint256) {
return length(map._inner);
}
function at(Bytes32ToUintMap storage map, uint256 index) internal view returns (bytes32, uint256) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (key, uint256(value));
}
function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool, uint256) {
(bool success, bytes32 value) = tryGet(map._inner, key);
return (success, uint256(value));
}
function get(Bytes32ToUintMap storage map, bytes32 key) internal view returns (uint256) {
return uint256(get(map._inner, key));
}
function get(
Bytes32ToUintMap storage map,
bytes32 key,
string memory errorMessage
) internal view returns (uint256) {
return uint256(get(map._inner, key, errorMessage));
}
}
文件 8 的 25:EnumerableMapAddresses.sol
pragma solidity ^0.8.0;
import {EnumerableMap} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableMap.sol";
library EnumerableMapAddresses {
using EnumerableMap for EnumerableMap.UintToAddressMap;
struct AddressToAddressMap {
EnumerableMap.UintToAddressMap _inner;
}
function set(AddressToAddressMap storage map, address key, address value) internal returns (bool) {
return map._inner.set(uint256(uint160(key)), value);
}
function remove(AddressToAddressMap storage map, address key) internal returns (bool) {
return map._inner.remove(uint256(uint160(key)));
}
function contains(AddressToAddressMap storage map, address key) internal view returns (bool) {
return map._inner.contains(uint256(uint160(key)));
}
function length(AddressToAddressMap storage map) internal view returns (uint256) {
return map._inner.length();
}
function at(AddressToAddressMap storage map, uint256 index) internal view returns (address, address) {
(uint256 key, address value) = map._inner.at(index);
return (address(uint160(key)), value);
}
function tryGet(AddressToAddressMap storage map, address key) internal view returns (bool, address) {
return map._inner.tryGet(uint256(uint160(key)));
}
function get(AddressToAddressMap storage map, address key) internal view returns (address) {
return map._inner.get(uint256(uint160(key)));
}
function get(
AddressToAddressMap storage map,
address key,
string memory errorMessage
) internal view returns (address) {
return map._inner.get(uint256(uint160(key)), errorMessage);
}
}
文件 9 的 25: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;
}
}
文件 10 的 25:IARM.sol
pragma solidity ^0.8.0;
interface IARM {
struct TaggedRoot {
address commitStore;
bytes32 root;
}
function isBlessed(TaggedRoot calldata taggedRoot) external view returns (bool);
function isCursed() external view returns (bool);
}
文件 11 的 25:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
文件 12 的 25:IEVM2AnyOnRamp.sol
pragma solidity ^0.8.0;
import {IEVM2AnyOnRampClient} from "./IEVM2AnyOnRampClient.sol";
import {Internal} from "../libraries/Internal.sol";
interface IEVM2AnyOnRamp is IEVM2AnyOnRampClient {
function getExpectedNextSequenceNumber() external view returns (uint64);
function getSenderNonce(address sender) external view returns (uint64 nonce);
function applyPoolUpdates(Internal.PoolUpdate[] memory removes, Internal.PoolUpdate[] memory adds) external;
}
文件 13 的 25:IEVM2AnyOnRampClient.sol
pragma solidity ^0.8.0;
import {IPool} from "./pools/IPool.sol";
import {Client} from "../libraries/Client.sol";
import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol";
interface IEVM2AnyOnRampClient {
function getFee(uint64 destChainSelector, Client.EVM2AnyMessage calldata message) external view returns (uint256 fee);
function getPoolBySourceToken(uint64 destChainSelector, IERC20 sourceToken) external view returns (IPool);
function getSupportedTokens(uint64 destChainSelector) external view returns (address[] memory tokens);
function forwardFromRouter(
uint64 destChainSelector,
Client.EVM2AnyMessage memory message,
uint256 feeTokenAmount,
address originalSender
) external returns (bytes32);
}
文件 14 的 25:ILinkAvailable.sol
pragma solidity ^0.8.0;
interface ILinkAvailable {
function linkAvailableForPayment() external view returns (int256 availableBalance);
}
文件 15 的 25:IOwnable.sol
pragma solidity ^0.8.0;
interface IOwnable {
function owner() external returns (address);
function transferOwnership(address recipient) external;
function acceptOwnership() external;
}
文件 16 的 25:IPool.sol
pragma solidity ^0.8.0;
import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol";
interface IPool {
function lockOrBurn(
address originalSender,
bytes calldata receiver,
uint256 amount,
uint64 destChainSelector,
bytes calldata extraArgs
) external returns (bytes memory);
function releaseOrMint(
bytes memory originalSender,
address receiver,
uint256 amount,
uint64 sourceChainSelector,
bytes memory extraData
) external;
function getToken() external view returns (IERC20 token);
}
文件 17 的 25: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.TimestampedPackedUint224 memory);
function getValidatedTokenPrice(address token) external view returns (uint224);
function getTokenPrices(address[] calldata tokens) external view returns (Internal.TimestampedPackedUint224[] memory);
function getDestinationChainGasPrice(
uint64 destChainSelector
) external view returns (Internal.TimestampedPackedUint224 memory);
function getTokenAndGasPrices(
address token,
uint64 destChainSelector
) external view returns (uint224 tokenPrice, uint224 gasPrice);
function convertTokenAmount(
address fromToken,
uint256 fromTokenAmount,
address toToken
) external view returns (uint256 toTokenAmount);
}
文件 18 的 25:ITypeAndVersion.sol
pragma solidity ^0.8.0;
interface ITypeAndVersion {
function typeAndVersion() external pure returns (string memory);
}
文件 19 的 25:Internal.sol
pragma solidity ^0.8.0;
import {Client} from "./Client.sol";
import {MerkleMultiProof} from "../libraries/MerkleMultiProof.sol";
library Internal {
uint16 internal constant GAS_FOR_CALL_EXACT_CHECK = 5_000;
uint16 internal constant MAX_RET_BYTES = 4 + 4 * 32;
struct PriceUpdates {
TokenPriceUpdate[] tokenPriceUpdates;
GasPriceUpdate[] gasPriceUpdates;
}
struct TokenPriceUpdate {
address sourceToken;
uint224 usdPerToken;
}
struct GasPriceUpdate {
uint64 destChainSelector;
uint224 usdPerUnitGas;
}
struct TimestampedPackedUint224 {
uint224 value;
uint32 timestamp;
}
uint8 public constant GAS_PRICE_BITS = 112;
struct PoolUpdate {
address token;
address pool;
}
struct ExecutionReport {
EVM2EVMMessage[] messages;
bytes[][] offchainTokenData;
bytes32[] proofs;
uint256 proofFlagBits;
}
struct EVM2EVMMessage {
uint64 sourceChainSelector;
address sender;
address receiver;
uint64 sequenceNumber;
uint256 gasLimit;
bool strict;
uint64 nonce;
address feeToken;
uint256 feeTokenAmount;
bytes data;
Client.EVMTokenAmount[] tokenAmounts;
bytes[] sourceTokenData;
bytes32 messageId;
}
uint256 public constant MESSAGE_FIXED_BYTES = 32 * 17;
uint256 public constant MESSAGE_FIXED_BYTES_PER_TOKEN = 32 * 4;
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("EVM2EVMMessageHashV2");
function _hash(EVM2EVMMessage memory original, bytes32 metadataHash) internal pure returns (bytes32) {
return
keccak256(
abi.encode(
MerkleMultiProof.LEAF_DOMAIN_SEPARATOR,
metadataHash,
keccak256(
abi.encode(
original.sender,
original.receiver,
original.sequenceNumber,
original.gasLimit,
original.strict,
original.nonce,
original.feeToken,
original.feeTokenAmount
)
),
keccak256(original.data),
keccak256(abi.encode(original.tokenAmounts)),
keccak256(abi.encode(original.sourceTokenData))
)
);
}
enum MessageExecutionState {
UNTOUCHED,
IN_PROGRESS,
SUCCESS,
FAILURE
}
}
文件 20 的 25: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);
}
}
文件 21 的 25:OwnerIsCreator.sol
pragma solidity ^0.8.0;
import {ConfirmedOwner} from "./ConfirmedOwner.sol";
contract OwnerIsCreator is ConfirmedOwner {
constructor() ConfirmedOwner(msg.sender) {}
}
文件 22 的 25:RateLimiter.sol
pragma solidity ^0.8.0;
library RateLimiter {
error BucketOverfilled();
error OnlyCallableByAdminOrOwner();
error TokenMaxCapacityExceeded(uint256 capacity, uint256 requested, address tokenAddress);
error TokenRateLimitReached(uint256 minWaitInSeconds, uint256 available, address tokenAddress);
error AggregateValueMaxCapacityExceeded(uint256 capacity, uint256 requested);
error AggregateValueRateLimitReached(uint256 minWaitInSeconds, uint256 available);
event TokensConsumed(uint256 tokens);
event ConfigChanged(Config config);
struct TokenBucket {
uint128 tokens;
uint32 lastUpdated;
bool isEnabled;
uint128 capacity;
uint128 rate;
}
struct Config {
bool isEnabled;
uint128 capacity;
uint128 rate;
}
function _consume(TokenBucket storage s_bucket, uint256 requestTokens, address tokenAddress) internal {
if (!s_bucket.isEnabled || requestTokens == 0) {
return;
}
uint256 tokens = s_bucket.tokens;
uint256 capacity = s_bucket.capacity;
uint256 timeDiff = block.timestamp - s_bucket.lastUpdated;
if (timeDiff != 0) {
if (tokens > capacity) revert BucketOverfilled();
tokens = _calculateRefill(capacity, tokens, timeDiff, s_bucket.rate);
s_bucket.lastUpdated = uint32(block.timestamp);
}
if (capacity < requestTokens) {
if (tokenAddress == address(0)) revert AggregateValueMaxCapacityExceeded(capacity, requestTokens);
revert TokenMaxCapacityExceeded(capacity, requestTokens, tokenAddress);
}
if (tokens < requestTokens) {
uint256 rate = s_bucket.rate;
uint256 minWaitInSeconds = ((requestTokens - tokens) + (rate - 1)) / rate;
if (tokenAddress == address(0)) revert AggregateValueRateLimitReached(minWaitInSeconds, tokens);
revert TokenRateLimitReached(minWaitInSeconds, tokens, tokenAddress);
}
tokens -= requestTokens;
s_bucket.tokens = uint128(tokens);
emit TokensConsumed(requestTokens);
}
function _currentTokenBucketState(TokenBucket memory bucket) internal view returns (TokenBucket memory) {
bucket.tokens = uint128(
_calculateRefill(bucket.capacity, bucket.tokens, block.timestamp - bucket.lastUpdated, bucket.rate)
);
bucket.lastUpdated = uint32(block.timestamp);
return bucket;
}
function _setTokenBucketConfig(TokenBucket storage s_bucket, Config memory config) internal {
uint256 timeDiff = block.timestamp - s_bucket.lastUpdated;
if (timeDiff != 0) {
s_bucket.tokens = uint128(_calculateRefill(s_bucket.capacity, s_bucket.tokens, timeDiff, s_bucket.rate));
s_bucket.lastUpdated = uint32(block.timestamp);
}
s_bucket.tokens = uint128(_min(config.capacity, s_bucket.tokens));
s_bucket.isEnabled = config.isEnabled;
s_bucket.capacity = config.capacity;
s_bucket.rate = config.rate;
emit ConfigChanged(config);
}
function _calculateRefill(
uint256 capacity,
uint256 tokens,
uint256 timeDiff,
uint256 rate
) private pure returns (uint256) {
return _min(capacity, tokens + timeDiff * rate);
}
function _min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
}
文件 23 的 25:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 24 的 25:USDPriceWith18Decimals.sol
pragma solidity ^0.8.0;
library USDPriceWith18Decimals {
function _calcUSDValueFromTokenAmount(uint224 tokenPrice, uint256 tokenAmount) internal pure returns (uint256) {
return (tokenPrice * tokenAmount) / 1e18;
}
function _calcTokenAmountFromUSDValue(uint224 tokenPrice, uint256 usdValue) internal pure returns (uint256) {
return (usdValue * 1e18) / tokenPrice;
}
}
文件 25 的 25:draft-IERC20Permit.sol
pragma solidity ^0.8.0;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
{
"compilationTarget": {
"src/v0.8/ccip/onRamp/EVM2EVMOnRamp.sol": "EVM2EVMOnRamp"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "none"
},
"optimizer": {
"enabled": true,
"runs": 10000
},
"remappings": [
":@ensdomains/=node_modules/@ensdomains/",
":@eth-optimism/=node_modules/@eth-optimism/",
":@openzeppelin/=node_modules/@openzeppelin/",
":ds-test/=foundry-lib/forge-std/lib/ds-test/src/",
":eth-gas-reporter/=node_modules/eth-gas-reporter/",
":forge-std/=foundry-lib/forge-std/src/",
":hardhat/=node_modules/hardhat/"
]
}
[{"inputs":[{"components":[{"internalType":"address","name":"linkToken","type":"address"},{"internalType":"uint64","name":"chainSelector","type":"uint64"},{"internalType":"uint64","name":"destChainSelector","type":"uint64"},{"internalType":"uint64","name":"defaultTxGasLimit","type":"uint64"},{"internalType":"uint96","name":"maxNopFeesJuels","type":"uint96"},{"internalType":"address","name":"prevOnRamp","type":"address"},{"internalType":"address","name":"armProxy","type":"address"}],"internalType":"struct EVM2EVMOnRamp.StaticConfig","name":"staticConfig","type":"tuple"},{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"uint16","name":"maxNumberOfTokensPerMsg","type":"uint16"},{"internalType":"uint32","name":"destGasOverhead","type":"uint32"},{"internalType":"uint16","name":"destGasPerPayloadByte","type":"uint16"},{"internalType":"uint32","name":"destDataAvailabilityOverheadGas","type":"uint32"},{"internalType":"uint16","name":"destGasPerDataAvailabilityByte","type":"uint16"},{"internalType":"uint16","name":"destDataAvailabilityMultiplierBps","type":"uint16"},{"internalType":"address","name":"priceRegistry","type":"address"},{"internalType":"uint32","name":"maxDataBytes","type":"uint32"},{"internalType":"uint32","name":"maxPerMsgGasLimit","type":"uint32"}],"internalType":"struct EVM2EVMOnRamp.DynamicConfig","name":"dynamicConfig","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"pool","type":"address"}],"internalType":"struct Internal.PoolUpdate[]","name":"tokensAndPools","type":"tuple[]"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.Config","name":"rateLimiterConfig","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint32","name":"networkFeeUSDCents","type":"uint32"},{"internalType":"uint64","name":"gasMultiplierWeiPerEth","type":"uint64"},{"internalType":"uint64","name":"premiumMultiplierWeiPerEth","type":"uint64"},{"internalType":"bool","name":"enabled","type":"bool"}],"internalType":"struct EVM2EVMOnRamp.FeeTokenConfigArgs[]","name":"feeTokenConfigs","type":"tuple[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint32","name":"minFeeUSDCents","type":"uint32"},{"internalType":"uint32","name":"maxFeeUSDCents","type":"uint32"},{"internalType":"uint16","name":"deciBps","type":"uint16"},{"internalType":"uint32","name":"destGasOverhead","type":"uint32"},{"internalType":"uint32","name":"destBytesOverhead","type":"uint32"}],"internalType":"struct EVM2EVMOnRamp.TokenTransferFeeConfigArgs[]","name":"tokenTransferFeeConfigArgs","type":"tuple[]"},{"components":[{"internalType":"address","name":"nop","type":"address"},{"internalType":"uint16","name":"weight","type":"uint16"}],"internalType":"struct EVM2EVMOnRamp.NopAndWeight[]","name":"nopsAndWeights","type":"tuple[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"capacity","type":"uint256"},{"internalType":"uint256","name":"requested","type":"uint256"}],"name":"AggregateValueMaxCapacityExceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"minWaitInSeconds","type":"uint256"},{"internalType":"uint256","name":"available","type":"uint256"}],"name":"AggregateValueRateLimitReached","type":"error"},{"inputs":[],"name":"BadARMSignal","type":"error"},{"inputs":[],"name":"BucketOverfilled","type":"error"},{"inputs":[],"name":"CannotSendZeroTokens","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[{"internalType":"bytes","name":"encodedAddress","type":"bytes"}],"name":"InvalidAddress","type":"error"},{"inputs":[{"internalType":"uint64","name":"chainSelector","type":"uint64"}],"name":"InvalidChainSelector","type":"error"},{"inputs":[],"name":"InvalidConfig","type":"error"},{"inputs":[],"name":"InvalidExtraArgsTag","type":"error"},{"inputs":[{"internalType":"address","name":"nop","type":"address"}],"name":"InvalidNopAddress","type":"error"},{"inputs":[],"name":"InvalidTokenPoolConfig","type":"error"},{"inputs":[],"name":"InvalidWithdrawParams","type":"error"},{"inputs":[],"name":"LinkBalanceNotSettled","type":"error"},{"inputs":[],"name":"MaxFeeBalanceReached","type":"error"},{"inputs":[],"name":"MessageGasLimitTooHigh","type":"error"},{"inputs":[{"internalType":"uint256","name":"maxSize","type":"uint256"},{"internalType":"uint256","name":"actualSize","type":"uint256"}],"name":"MessageTooLarge","type":"error"},{"inputs":[],"name":"MustBeCalledByRouter","type":"error"},{"inputs":[],"name":"NoFeesToPay","type":"error"},{"inputs":[],"name":"NoNopsToPay","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"NotAFeeToken","type":"error"},{"inputs":[],"name":"OnlyCallableByAdminOrOwner","type":"error"},{"inputs":[],"name":"OnlyCallableByOwnerOrAdmin","type":"error"},{"inputs":[],"name":"OnlyCallableByOwnerOrAdminOrNop","type":"error"},{"inputs":[],"name":"PoolAlreadyAdded","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"PoolDoesNotExist","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"PriceNotFoundForToken","type":"error"},{"inputs":[],"name":"RouterMustSetOriginalSender","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SourceTokenDataTooLarge","type":"error"},{"inputs":[{"internalType":"uint256","name":"capacity","type":"uint256"},{"internalType":"uint256","name":"requested","type":"uint256"},{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"TokenMaxCapacityExceeded","type":"error"},{"inputs":[],"name":"TokenPoolMismatch","type":"error"},{"inputs":[{"internalType":"uint256","name":"minWaitInSeconds","type":"uint256"},{"internalType":"uint256","name":"available","type":"uint256"},{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"TokenRateLimitReached","type":"error"},{"inputs":[],"name":"TooManyNops","type":"error"},{"inputs":[],"name":"UnsupportedNumberOfTokens","type":"error"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"UnsupportedToken","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminSet","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint64","name":"sequenceNumber","type":"uint64"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"bool","name":"strict","type":"bool"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"uint256","name":"feeTokenAmount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Client.EVMTokenAmount[]","name":"tokenAmounts","type":"tuple[]"},{"internalType":"bytes[]","name":"sourceTokenData","type":"bytes[]"},{"internalType":"bytes32","name":"messageId","type":"bytes32"}],"indexed":false,"internalType":"struct Internal.EVM2EVMMessage","name":"message","type":"tuple"}],"name":"CCIPSendRequested","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"linkToken","type":"address"},{"internalType":"uint64","name":"chainSelector","type":"uint64"},{"internalType":"uint64","name":"destChainSelector","type":"uint64"},{"internalType":"uint64","name":"defaultTxGasLimit","type":"uint64"},{"internalType":"uint96","name":"maxNopFeesJuels","type":"uint96"},{"internalType":"address","name":"prevOnRamp","type":"address"},{"internalType":"address","name":"armProxy","type":"address"}],"indexed":false,"internalType":"struct EVM2EVMOnRamp.StaticConfig","name":"staticConfig","type":"tuple"},{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"uint16","name":"maxNumberOfTokensPerMsg","type":"uint16"},{"internalType":"uint32","name":"destGasOverhead","type":"uint32"},{"internalType":"uint16","name":"destGasPerPayloadByte","type":"uint16"},{"internalType":"uint32","name":"destDataAvailabilityOverheadGas","type":"uint32"},{"internalType":"uint16","name":"destGasPerDataAvailabilityByte","type":"uint16"},{"internalType":"uint16","name":"destDataAvailabilityMultiplierBps","type":"uint16"},{"internalType":"address","name":"priceRegistry","type":"address"},{"internalType":"uint32","name":"maxDataBytes","type":"uint32"},{"internalType":"uint32","name":"maxPerMsgGasLimit","type":"uint32"}],"indexed":false,"internalType":"struct EVM2EVMOnRamp.DynamicConfig","name":"dynamicConfig","type":"tuple"}],"name":"ConfigSet","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint32","name":"networkFeeUSDCents","type":"uint32"},{"internalType":"uint64","name":"gasMultiplierWeiPerEth","type":"uint64"},{"internalType":"uint64","name":"premiumMultiplierWeiPerEth","type":"uint64"},{"internalType":"bool","name":"enabled","type":"bool"}],"indexed":false,"internalType":"struct EVM2EVMOnRamp.FeeTokenConfigArgs[]","name":"feeConfig","type":"tuple[]"}],"name":"FeeConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nop","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"NopPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"nopWeightsTotal","type":"uint256"},{"components":[{"internalType":"address","name":"nop","type":"address"},{"internalType":"uint16","name":"weight","type":"uint16"}],"indexed":false,"internalType":"struct EVM2EVMOnRamp.NopAndWeight[]","name":"nopsAndWeights","type":"tuple[]"}],"name":"NopsSet","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":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"pool","type":"address"}],"name":"PoolAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"pool","type":"address"}],"name":"PoolRemoved","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint32","name":"minFeeUSDCents","type":"uint32"},{"internalType":"uint32","name":"maxFeeUSDCents","type":"uint32"},{"internalType":"uint16","name":"deciBps","type":"uint16"},{"internalType":"uint32","name":"destGasOverhead","type":"uint32"},{"internalType":"uint32","name":"destBytesOverhead","type":"uint32"}],"indexed":false,"internalType":"struct EVM2EVMOnRamp.TokenTransferFeeConfigArgs[]","name":"transferFeeConfig","type":"tuple[]"}],"name":"TokenTransferFeeConfigSet","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"pool","type":"address"}],"internalType":"struct Internal.PoolUpdate[]","name":"removes","type":"tuple[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"pool","type":"address"}],"internalType":"struct Internal.PoolUpdate[]","name":"adds","type":"tuple[]"}],"name":"applyPoolUpdates","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentRateLimiterState","outputs":[{"components":[{"internalType":"uint128","name":"tokens","type":"uint128"},{"internalType":"uint32","name":"lastUpdated","type":"uint32"},{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.TokenBucket","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"destChainSelector","type":"uint64"},{"components":[{"internalType":"bytes","name":"receiver","type":"bytes"},{"internalType":"bytes","name":"data","type":"bytes"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Client.EVMTokenAmount[]","name":"tokenAmounts","type":"tuple[]"},{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"bytes","name":"extraArgs","type":"bytes"}],"internalType":"struct Client.EVM2AnyMessage","name":"message","type":"tuple"},{"internalType":"uint256","name":"feeTokenAmount","type":"uint256"},{"internalType":"address","name":"originalSender","type":"address"}],"name":"forwardFromRouter","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getDynamicConfig","outputs":[{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"uint16","name":"maxNumberOfTokensPerMsg","type":"uint16"},{"internalType":"uint32","name":"destGasOverhead","type":"uint32"},{"internalType":"uint16","name":"destGasPerPayloadByte","type":"uint16"},{"internalType":"uint32","name":"destDataAvailabilityOverheadGas","type":"uint32"},{"internalType":"uint16","name":"destGasPerDataAvailabilityByte","type":"uint16"},{"internalType":"uint16","name":"destDataAvailabilityMultiplierBps","type":"uint16"},{"internalType":"address","name":"priceRegistry","type":"address"},{"internalType":"uint32","name":"maxDataBytes","type":"uint32"},{"internalType":"uint32","name":"maxPerMsgGasLimit","type":"uint32"}],"internalType":"struct EVM2EVMOnRamp.DynamicConfig","name":"dynamicConfig","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExpectedNextSequenceNumber","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"destChainSelector","type":"uint64"},{"components":[{"internalType":"bytes","name":"receiver","type":"bytes"},{"internalType":"bytes","name":"data","type":"bytes"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Client.EVMTokenAmount[]","name":"tokenAmounts","type":"tuple[]"},{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"bytes","name":"extraArgs","type":"bytes"}],"internalType":"struct Client.EVM2AnyMessage","name":"message","type":"tuple"}],"name":"getFee","outputs":[{"internalType":"uint256","name":"feeTokenAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getFeeTokenConfig","outputs":[{"components":[{"internalType":"uint32","name":"networkFeeUSDCents","type":"uint32"},{"internalType":"uint64","name":"gasMultiplierWeiPerEth","type":"uint64"},{"internalType":"uint64","name":"premiumMultiplierWeiPerEth","type":"uint64"},{"internalType":"bool","name":"enabled","type":"bool"}],"internalType":"struct EVM2EVMOnRamp.FeeTokenConfig","name":"feeTokenConfig","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNopFeesJuels","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNops","outputs":[{"components":[{"internalType":"address","name":"nop","type":"address"},{"internalType":"uint16","name":"weight","type":"uint16"}],"internalType":"struct EVM2EVMOnRamp.NopAndWeight[]","name":"nopsAndWeights","type":"tuple[]"},{"internalType":"uint256","name":"weightsTotal","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"},{"internalType":"contract IERC20","name":"sourceToken","type":"address"}],"name":"getPoolBySourceToken","outputs":[{"internalType":"contract IPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"getSenderNonce","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStaticConfig","outputs":[{"components":[{"internalType":"address","name":"linkToken","type":"address"},{"internalType":"uint64","name":"chainSelector","type":"uint64"},{"internalType":"uint64","name":"destChainSelector","type":"uint64"},{"internalType":"uint64","name":"defaultTxGasLimit","type":"uint64"},{"internalType":"uint96","name":"maxNopFeesJuels","type":"uint96"},{"internalType":"address","name":"prevOnRamp","type":"address"},{"internalType":"address","name":"armProxy","type":"address"}],"internalType":"struct EVM2EVMOnRamp.StaticConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"}],"name":"getSupportedTokens","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTokenLimitAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getTokenTransferFeeConfig","outputs":[{"components":[{"internalType":"uint32","name":"minFeeUSDCents","type":"uint32"},{"internalType":"uint32","name":"maxFeeUSDCents","type":"uint32"},{"internalType":"uint16","name":"deciBps","type":"uint16"},{"internalType":"uint32","name":"destGasOverhead","type":"uint32"},{"internalType":"uint32","name":"destBytesOverhead","type":"uint32"}],"internalType":"struct EVM2EVMOnRamp.TokenTransferFeeConfig","name":"tokenTransferFeeConfig","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"linkAvailableForPayment","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"payNops","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"uint16","name":"maxNumberOfTokensPerMsg","type":"uint16"},{"internalType":"uint32","name":"destGasOverhead","type":"uint32"},{"internalType":"uint16","name":"destGasPerPayloadByte","type":"uint16"},{"internalType":"uint32","name":"destDataAvailabilityOverheadGas","type":"uint32"},{"internalType":"uint16","name":"destGasPerDataAvailabilityByte","type":"uint16"},{"internalType":"uint16","name":"destDataAvailabilityMultiplierBps","type":"uint16"},{"internalType":"address","name":"priceRegistry","type":"address"},{"internalType":"uint32","name":"maxDataBytes","type":"uint32"},{"internalType":"uint32","name":"maxPerMsgGasLimit","type":"uint32"}],"internalType":"struct EVM2EVMOnRamp.DynamicConfig","name":"dynamicConfig","type":"tuple"}],"name":"setDynamicConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint32","name":"networkFeeUSDCents","type":"uint32"},{"internalType":"uint64","name":"gasMultiplierWeiPerEth","type":"uint64"},{"internalType":"uint64","name":"premiumMultiplierWeiPerEth","type":"uint64"},{"internalType":"bool","name":"enabled","type":"bool"}],"internalType":"struct EVM2EVMOnRamp.FeeTokenConfigArgs[]","name":"feeTokenConfigArgs","type":"tuple[]"}],"name":"setFeeTokenConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"nop","type":"address"},{"internalType":"uint16","name":"weight","type":"uint16"}],"internalType":"struct EVM2EVMOnRamp.NopAndWeight[]","name":"nopsAndWeights","type":"tuple[]"}],"name":"setNops","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.Config","name":"config","type":"tuple"}],"name":"setRateLimiterConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint32","name":"minFeeUSDCents","type":"uint32"},{"internalType":"uint32","name":"maxFeeUSDCents","type":"uint32"},{"internalType":"uint16","name":"deciBps","type":"uint16"},{"internalType":"uint32","name":"destGasOverhead","type":"uint32"},{"internalType":"uint32","name":"destBytesOverhead","type":"uint32"}],"internalType":"struct EVM2EVMOnRamp.TokenTransferFeeConfigArgs[]","name":"tokenTransferFeeConfigArgs","type":"tuple[]"}],"name":"setTokenTransferFeeConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"typeAndVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawNonLinkFees","outputs":[],"stateMutability":"nonpayable","type":"function"}]