编译器
0.8.23+commit.f704f362
文件 1 的 13:CCIPReceiver.sol
pragma solidity ^0.8.0;
import {IAny2EVMMessageReceiver} from "../interfaces/IAny2EVMMessageReceiver.sol";
import {Client} from "../libraries/Client.sol";
import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol";
abstract contract CCIPReceiver is IAny2EVMMessageReceiver, IERC165 {
address internal immutable i_ccipRouter;
constructor(address router) {
if (router == address(0)) revert InvalidRouter(address(0));
i_ccipRouter = router;
}
function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {
return interfaceId == type(IAny2EVMMessageReceiver).interfaceId || interfaceId == type(IERC165).interfaceId;
}
function ccipReceive(Client.Any2EVMMessage calldata message) external virtual override onlyRouter {
_ccipReceive(message);
}
function _ccipReceive(Client.Any2EVMMessage memory message) internal virtual;
function getRouter() public view returns (address) {
return address(i_ccipRouter);
}
error InvalidRouter(address router);
modifier onlyRouter() {
if (msg.sender != address(i_ccipRouter)) revert InvalidRouter(msg.sender);
_;
}
}
文件 2 的 13:CCIPxERC20Bridge.sol
pragma solidity ^0.8.19;
import {CCIPReceiver} from "ccip/src/v0.8/ccip/applications/CCIPReceiver.sol";
import {IRouterClient} from "ccip/src/v0.8/ccip/interfaces/IRouterClient.sol";
import {Client} from "ccip/src/v0.8/ccip/libraries/Client.sol";
import {OwnerIsCreator} from "ccip/src/v0.8/shared/access/OwnerIsCreator.sol";
import {IERC20} from "ccip/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
import {IXERC20} from "xERC20/solidity/interfaces/IXERC20.sol";
import {IXERC20Lockbox} from "xERC20/solidity/interfaces/IXERC20Lockbox.sol";
contract CCIPxERC20Bridge is CCIPReceiver, OwnerIsCreator {
error NotEnoughBalance(uint256 currentBalance, uint256 calculatedFees);
error NothingToWithdraw();
error FailedToWithdrawEth(address owner, address target, uint256 value);
error SenderNotAllowlistedBySourceChain(
uint64 sourceChainSelector,
address sender
);
error NoReceiverForDestinationChain(uint64 destinationChainSelector);
event MessageSent(
bytes32 indexed messageId,
uint64 indexed destinationChainSelector,
address receiver,
address recipient,
uint256 amount,
address feeToken,
uint256 fees
);
event MessageReceived(
bytes32 indexed messageId,
uint64 indexed sourceChainSelector,
address sender,
uint256 amount,
address recipient
);
bytes32 private _lastReceivedMessageId;
string private _lastReceivedText;
mapping(uint64 => address) public bridgesByChain;
IERC20 public linkToken;
struct XERC20Config {
IERC20 erc20;
IXERC20Lockbox lockbox;
}
mapping(IXERC20 => XERC20Config) public xerc20s;
mapping(uint64 => mapping(address => address)) public xerc20sByChain;
mapping(uint32 => uint64) public chainIdToChainSelector;
uint256 public feeBps;
constructor(
address _router,
address _link,
uint256 _feeBps
) CCIPReceiver(_router) {
linkToken = IERC20(_link);
feeBps = _feeBps;
chainIdToChainSelector[11_155_111] = 16_015_286_601_757_825_753;
chainIdToChainSelector[421_614] = 3_478_487_238_524_512_106;
chainIdToChainSelector[80_001] = 12_532_609_583_862_916_517;
chainIdToChainSelector[1] = 5_009_297_550_715_157_269;
chainIdToChainSelector[10] = 3_734_403_246_176_062_136;
chainIdToChainSelector[56] = 11_344_663_589_394_136_015;
chainIdToChainSelector[137] = 4_051_577_828_743_386_545;
chainIdToChainSelector[8453] = 15_971_525_489_660_198_786;
chainIdToChainSelector[43_114] = 6_433_500_567_565_415_381;
chainIdToChainSelector[42_161] = 4_949_039_107_694_359_620;
}
modifier onlyAllowlistedSenderBySourceChain(
uint64 _sourceChainSelector,
address _sender
) {
if (bridgesByChain[_sourceChainSelector] != _sender) {
revert SenderNotAllowlistedBySourceChain(
_sourceChainSelector,
_sender
);
}
_;
}
modifier validReceiver(uint64 _destinationChainSelector) {
if (bridgesByChain[_destinationChainSelector] == address(0)) {
revert NoReceiverForDestinationChain(_destinationChainSelector);
}
_;
}
function addXERC20ForOriginChain(
uint64 _chainSelector,
address _xerc20remote,
address _xerc20local
) external onlyOwner {
xerc20sByChain[_chainSelector][_xerc20remote] = _xerc20local;
}
function addXERC20Config(
IXERC20 _xerc20,
IERC20 _erc20,
IXERC20Lockbox _lockbox
) external onlyOwner {
xerc20s[IXERC20(_xerc20)] = XERC20Config({
erc20: IERC20(_erc20),
lockbox: IXERC20Lockbox(_lockbox)
});
}
function addBridgeForChain(
uint64 _chainSelector,
address _bridge
) external onlyOwner {
bridgesByChain[_chainSelector] = _bridge;
}
function addChainIdToChainSelector(
uint32 _chainId,
uint64 _chainSelector
) external onlyOwner {
chainIdToChainSelector[_chainId] = _chainSelector;
}
function setFeeBps(uint256 _feeBps) external onlyOwner {
feeBps = _feeBps;
}
function getFee(
address _xerc20,
uint32 _destinationChainId,
uint256 _amount,
bool _feeInLINK
) external view returns (uint256) {
uint64 _destinationChainSelector = chainIdToChainSelector[
_destinationChainId
];
address _receiver = bridgesByChain[_destinationChainSelector];
IRouterClient router = IRouterClient(this.getRouter());
Client.EVM2AnyMessage memory evm2AnyMessage = _buildCCIPMessage(
_xerc20,
_receiver,
_amount,
msg.sender,
_feeInLINK ? address(linkToken) : address(0)
);
return router.getFee(_destinationChainSelector, evm2AnyMessage);
}
function bridgeTokens(
address _xerc20,
uint32 _destinationChainId,
address _receipient,
uint256 _amount
) external payable returns (bytes32 messageId) {
return
_bridgeTokens(
_xerc20,
_destinationChainId,
_receipient,
_amount,
false
);
}
function bridgeTokensWithLINK(
address _xerc20,
uint32 _destinationChainId,
address _receipient,
uint256 _amount
) external returns (bytes32 messageId) {
return
_bridgeTokens(
_xerc20,
_destinationChainId,
_receipient,
_amount,
true
);
}
function _bridgeTokens(
address _xerc20,
uint32 _destinationChainId,
address _receipient,
uint256 _amount,
bool _feeInLINK
)
internal
validReceiver(chainIdToChainSelector[_destinationChainId])
returns (bytes32 messageId)
{
uint64 _destinationChainSelector = chainIdToChainSelector[
_destinationChainId
];
address _receiver = bridgesByChain[_destinationChainSelector];
if (address(xerc20s[IXERC20(_xerc20)].lockbox) == address(0)) {
IERC20(address(_xerc20)).transferFrom(
msg.sender,
address(this),
_amount
);
} else {
xerc20s[IXERC20(_xerc20)].erc20.transferFrom(
msg.sender,
address(this),
_amount
);
xerc20s[IXERC20(_xerc20)].erc20.approve(
address(xerc20s[IXERC20(_xerc20)].lockbox),
_amount
);
xerc20s[IXERC20(_xerc20)].lockbox.deposit(_amount);
}
uint256 _bridgedAmount = _amount - ((_amount * feeBps) / 10_000);
IXERC20(_xerc20).burn(address(this), _bridgedAmount);
address _feeToken = _feeInLINK ? address(linkToken) : address(0);
Client.EVM2AnyMessage memory evm2AnyMessage = _buildCCIPMessage(
_xerc20,
_receiver,
_bridgedAmount,
_receipient,
_feeToken
);
IRouterClient router = IRouterClient(this.getRouter());
uint256 fees = router.getFee(_destinationChainSelector, evm2AnyMessage);
if (_feeInLINK) {
linkToken.transferFrom(msg.sender, address(this), fees);
linkToken.approve(address(router), fees);
} else {
if (msg.value < fees) {
revert NotEnoughBalance(address(this).balance, fees);
}
uint256 _refund = msg.value - fees;
if (_refund > 0) {
payable(msg.sender).transfer(_refund);
}
}
messageId = router.ccipSend{value: _feeInLINK ? 0 : fees}(
_destinationChainSelector,
evm2AnyMessage
);
emit MessageSent(
messageId,
_destinationChainSelector,
_receiver,
_receipient,
_bridgedAmount,
_feeToken,
fees
);
return messageId;
}
function _ccipReceive(
Client.Any2EVMMessage memory any2EvmMessage
)
internal
override
onlyAllowlistedSenderBySourceChain(
any2EvmMessage.sourceChainSelector,
abi.decode(any2EvmMessage.sender, (address))
)
{
_lastReceivedMessageId = any2EvmMessage.messageId;
(address _xerc20, uint256 _amount, address _recipient) = abi.decode(
any2EvmMessage.data,
(address, uint256, address)
);
address localXERC20 = xerc20sByChain[
any2EvmMessage.sourceChainSelector
][address(_xerc20)];
XERC20Config memory xerc20Config = xerc20s[IXERC20(localXERC20)];
if (address(xerc20Config.lockbox) == address(0)) {
IXERC20(localXERC20).mint(_recipient, _amount);
} else {
IXERC20(localXERC20).mint(address(this), _amount);
xerc20Config.lockbox.withdraw(_amount);
IERC20(address(xerc20Config.erc20)).transfer(_recipient, _amount);
}
emit MessageReceived(
any2EvmMessage.messageId,
any2EvmMessage.sourceChainSelector,
abi.decode(any2EvmMessage.sender, (address)),
_amount,
_recipient
);
}
function _buildCCIPMessage(
address _xerc20,
address _receiver,
uint256 _amount,
address _receipient,
address _feeTokenAddress
) internal pure returns (Client.EVM2AnyMessage memory) {
return
Client.EVM2AnyMessage({
receiver: abi.encode(_receiver),
data: abi.encode(_xerc20, _amount, _receipient),
tokenAmounts: new Client.EVMTokenAmount[](0),
extraArgs: Client._argsToBytes(
Client.EVMExtraArgsV1({gasLimit: 200_000})
),
feeToken: _feeTokenAddress
});
}
function getLastReceivedMessageDetails()
external
view
returns (bytes32 messageId, string memory text)
{
return (_lastReceivedMessageId, _lastReceivedText);
}
receive() external payable {}
function withdraw(address _beneficiary) public onlyOwner {
uint256 amount = address(this).balance;
if (amount == 0) revert NothingToWithdraw();
(bool sent, ) = _beneficiary.call{value: amount}("");
if (!sent) revert FailedToWithdrawEth(msg.sender, _beneficiary, amount);
}
function withdrawToken(
address _beneficiary,
address _token
) public onlyOwner {
uint256 amount = IERC20(_token).balanceOf(address(this));
if (amount == 0) revert NothingToWithdraw();
IERC20(_token).transfer(_beneficiary, amount);
}
}
文件 3 的 13: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 的 13:ConfirmedOwner.sol
pragma solidity ^0.8.0;
import {ConfirmedOwnerWithProposal} from "./ConfirmedOwnerWithProposal.sol";
contract ConfirmedOwner is ConfirmedOwnerWithProposal {
constructor(address newOwner) ConfirmedOwnerWithProposal(newOwner, address(0)) {}
}
文件 5 的 13: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 的 13:IAny2EVMMessageReceiver.sol
pragma solidity ^0.8.0;
import {Client} from "../libraries/Client.sol";
interface IAny2EVMMessageReceiver {
function ccipReceive(Client.Any2EVMMessage calldata message) external;
}
文件 7 的 13:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 8 的 13: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);
}
文件 9 的 13:IOwnable.sol
pragma solidity ^0.8.0;
interface IOwnable {
function owner() external returns (address);
function transferOwnership(address recipient) external;
function acceptOwnership() external;
}
文件 10 的 13:IRouterClient.sol
pragma solidity ^0.8.0;
import {Client} from "../libraries/Client.sol";
interface IRouterClient {
error UnsupportedDestinationChain(uint64 destChainSelector);
error InsufficientFeeTokenAmount();
error InvalidMsgValue();
function isChainSupported(uint64 chainSelector) external view returns (bool supported);
function getSupportedTokens(uint64 chainSelector) external view returns (address[] memory tokens);
function getFee(
uint64 destinationChainSelector,
Client.EVM2AnyMessage memory message
) external view returns (uint256 fee);
function ccipSend(
uint64 destinationChainSelector,
Client.EVM2AnyMessage calldata message
) external payable returns (bytes32);
}
文件 11 的 13:IXERC20.sol
pragma solidity >=0.8.4 <0.9.0;
interface IXERC20 {
event LockboxSet(address _lockbox);
event BridgeLimitsSet(uint256 _mintingLimit, uint256 _burningLimit, address indexed _bridge);
error IXERC20_NotHighEnoughLimits();
error IXERC20_NotFactory();
error IXERC20_LimitsTooHigh();
struct Bridge {
BridgeParameters minterParams;
BridgeParameters burnerParams;
}
struct BridgeParameters {
uint256 timestamp;
uint256 ratePerSecond;
uint256 maxLimit;
uint256 currentLimit;
}
function setLockbox(address _lockbox) external;
function setLimits(address _bridge, uint256 _mintingLimit, uint256 _burningLimit) external;
function mintingMaxLimitOf(address _minter) external view returns (uint256 _limit);
function burningMaxLimitOf(address _bridge) external view returns (uint256 _limit);
function mintingCurrentLimitOf(address _minter) external view returns (uint256 _limit);
function burningCurrentLimitOf(address _bridge) external view returns (uint256 _limit);
function mint(address _user, uint256 _amount) external;
function burn(address _user, uint256 _amount) external;
}
文件 12 的 13:IXERC20Lockbox.sol
pragma solidity >=0.8.4 <0.9.0;
interface IXERC20Lockbox {
event Deposit(address _sender, uint256 _amount);
event Withdraw(address _sender, uint256 _amount);
error IXERC20Lockbox_NotNative();
error IXERC20Lockbox_Native();
error IXERC20Lockbox_WithdrawFailed();
function deposit(uint256 _amount) external;
function depositTo(address _user, uint256 _amount) external;
function depositNativeTo(address _user) external payable;
function withdraw(uint256 _amount) external;
function withdrawTo(address _user, uint256 _amount) external;
}
文件 13 的 13:OwnerIsCreator.sol
pragma solidity ^0.8.0;
import {ConfirmedOwner} from "./ConfirmedOwner.sol";
contract OwnerIsCreator is ConfirmedOwner {
constructor() ConfirmedOwner(msg.sender) {}
}
{
"compilationTarget": {
"src/CCIPxERC20Bridge.sol": "CCIPxERC20Bridge"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [
":@openzeppelin/=lib/xERC20/lib/openzeppelin-contracts/",
":ccip/=lib/ccip/contracts/",
":ds-test/=lib/xERC20/lib/ds-test/src/",
":erc4626-tests/=lib/xERC20/lib/openzeppelin-contracts/lib/erc4626-tests/",
":forge-gas-snapshot/=lib/xERC20/lib/permit2/lib/forge-gas-snapshot/src/",
":forge-std/=lib/forge-std/src/",
":isolmate/=lib/xERC20/lib/isolmate/src/",
":openzeppelin-contracts/=lib/xERC20/lib/openzeppelin-contracts/",
":openzeppelin/=lib/xERC20/lib/openzeppelin-contracts/contracts/",
":permit2/=lib/xERC20/lib/permit2/",
":prb-test/=lib/xERC20/lib/prb-test/src/",
":prb/test/=lib/xERC20/lib/prb-test/src/",
":solmate/=lib/xERC20/lib/permit2/lib/solmate/",
":xERC20/=lib/xERC20/"
]
}
[{"inputs":[{"internalType":"address","name":"_router","type":"address"},{"internalType":"address","name":"_link","type":"address"},{"internalType":"uint256","name":"_feeBps","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"FailedToWithdrawEth","type":"error"},{"inputs":[{"internalType":"address","name":"router","type":"address"}],"name":"InvalidRouter","type":"error"},{"inputs":[{"internalType":"uint64","name":"destinationChainSelector","type":"uint64"}],"name":"NoReceiverForDestinationChain","type":"error"},{"inputs":[{"internalType":"uint256","name":"currentBalance","type":"uint256"},{"internalType":"uint256","name":"calculatedFees","type":"uint256"}],"name":"NotEnoughBalance","type":"error"},{"inputs":[],"name":"NothingToWithdraw","type":"error"},{"inputs":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"address","name":"sender","type":"address"}],"name":"SenderNotAllowlistedBySourceChain","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"messageId","type":"bytes32"},{"indexed":true,"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"}],"name":"MessageReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"messageId","type":"bytes32"},{"indexed":true,"internalType":"uint64","name":"destinationChainSelector","type":"uint64"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"feeToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"fees","type":"uint256"}],"name":"MessageSent","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"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_chainSelector","type":"uint64"},{"internalType":"address","name":"_bridge","type":"address"}],"name":"addBridgeForChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_chainId","type":"uint32"},{"internalType":"uint64","name":"_chainSelector","type":"uint64"}],"name":"addChainIdToChainSelector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IXERC20","name":"_xerc20","type":"address"},{"internalType":"contract IERC20","name":"_erc20","type":"address"},{"internalType":"contract IXERC20Lockbox","name":"_lockbox","type":"address"}],"name":"addXERC20Config","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_chainSelector","type":"uint64"},{"internalType":"address","name":"_xerc20remote","type":"address"},{"internalType":"address","name":"_xerc20local","type":"address"}],"name":"addXERC20ForOriginChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_xerc20","type":"address"},{"internalType":"uint32","name":"_destinationChainId","type":"uint32"},{"internalType":"address","name":"_receipient","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"bridgeTokens","outputs":[{"internalType":"bytes32","name":"messageId","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_xerc20","type":"address"},{"internalType":"uint32","name":"_destinationChainId","type":"uint32"},{"internalType":"address","name":"_receipient","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"bridgeTokensWithLINK","outputs":[{"internalType":"bytes32","name":"messageId","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"}],"name":"bridgesByChain","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"messageId","type":"bytes32"},{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"bytes","name":"sender","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":"destTokenAmounts","type":"tuple[]"}],"internalType":"struct Client.Any2EVMMessage","name":"message","type":"tuple"}],"name":"ccipReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"chainIdToChainSelector","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_xerc20","type":"address"},{"internalType":"uint32","name":"_destinationChainId","type":"uint32"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bool","name":"_feeInLINK","type":"bool"}],"name":"getFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastReceivedMessageDetails","outputs":[{"internalType":"bytes32","name":"messageId","type":"bytes32"},{"internalType":"string","name":"text","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRouter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"linkToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_feeBps","type":"uint256"}],"name":"setFeeBps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_beneficiary","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_beneficiary","type":"address"},{"internalType":"address","name":"_token","type":"address"}],"name":"withdrawToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IXERC20","name":"","type":"address"}],"name":"xerc20s","outputs":[{"internalType":"contract IERC20","name":"erc20","type":"address"},{"internalType":"contract IXERC20Lockbox","name":"lockbox","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"},{"internalType":"address","name":"","type":"address"}],"name":"xerc20sByChain","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]