编译器
0.8.19+commit.7dd6d404
文件 1 的 12: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 的 12: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.0/contracts/utils/introspection/IERC165.sol";
abstract contract CCIPReceiver is IAny2EVMMessageReceiver, IERC165 {
address internal immutable i_router;
constructor(address router) {
if (router == address(0)) revert InvalidRouter(address(0));
i_router = 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_router);
}
error InvalidRouter(address router);
modifier onlyRouter() {
if (msg.sender != address(i_router)) revert InvalidRouter(msg.sender);
_;
}
}
文件 3 的 12:CCIP_NEW.sol
pragma solidity 0.8.19;
import {IRouterClient} from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol";
import {Client} from "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol";
import {CCIPReceiver} from "@chainlink/contracts-ccip/src/v0.8/ccip/applications/CCIPReceiver.sol";
import {IERC20} from "@chainlink/contracts-ccip/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@chainlink/contracts-ccip/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol";
import {EnumerableMap} from "@chainlink/contracts-ccip/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableMap.sol";
interface IV3SwapRouter {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);
struct ExactInputParams {
bytes path;
address recipient;
uint256 amountIn;
uint256 amountOutMinimum;
}
function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut);
struct ExactOutputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 amountOut;
uint256 amountInMaximum;
uint160 sqrtPriceLimitX96;
}
function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn);
struct ExactOutputParams {
bytes path;
address recipient;
uint256 amountOut;
uint256 amountInMaximum;
}
function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn);
function uniswapV3SwapCallback(
int256 amount0Delta,
int256 amount1Delta,
bytes calldata data
) external;
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to
) external payable returns (uint256 amountOut);
function swapTokensForExactTokens(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to
) external payable returns (uint256 amountIn);
function WETH9() external view returns (address);
}
interface IUniswapV2Router02 {
function WETH() external pure returns (address);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external payable;
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
}
interface IWETH is IERC20 {
function deposit() external payable;
function withdraw(uint amount) external;
}
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
abstract contract Ownable is Context {
address private _owner;
error OwnableUnauthorizedAccount(address account);
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
library BytesLib {
function slice(
bytes memory _bytes,
uint256 _start,
uint256 _length
) internal pure returns (bytes memory) {
require(_length + 31 >= _length, 'slice_overflow');
require(_start + _length >= _start, 'slice_overflow');
require(_bytes.length >= _start + _length, 'slice_outOfBounds');
bytes memory tempBytes;
assembly {
switch iszero(_length)
case 0 {
tempBytes := mload(0x40)
let lengthmod := and(_length, 31)
let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
let end := add(mc, _length)
for {
let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
} lt(mc, end) {
mc := add(mc, 0x20)
cc := add(cc, 0x20)
} {
mstore(mc, mload(cc))
}
mstore(tempBytes, _length)
mstore(0x40, and(add(mc, 31), not(31)))
}
default {
tempBytes := mload(0x40)
mstore(tempBytes, 0)
mstore(0x40, add(tempBytes, 0x20))
}
}
return tempBytes;
}
function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
require(_start + 20 >= _start, 'toAddress_overflow');
require(_bytes.length >= _start + 20, 'toAddress_outOfBounds');
address tempAddress;
assembly {
tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
}
return tempAddress;
}
function toUint24(bytes memory _bytes, uint256 _start) internal pure returns (uint24) {
require(_start + 3 >= _start, 'toUint24_overflow');
require(_bytes.length >= _start + 3, 'toUint24_outOfBounds');
uint24 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x3), _start))
}
return tempUint;
}
}
contract CCIP is CCIPReceiver, Ownable {
using EnumerableMap for EnumerableMap.Bytes32ToUintMap;
using SafeERC20 for IERC20;
using BytesLib for bytes;
error NotEnoughBalance(uint256 currentBalance, uint256 calculatedFees);
error NothingToWithdraw();
error FailedToWithdrawEth(address owner, address target, uint256 value);
error DestinationChainNotAllowlisted(uint64 destinationChainSelector);
error SourceChainNotAllowed(uint64 sourceChainSelector);
error SenderNotAllowed(address sender);
error InvalidReceiverAddress();
error OnlySelf();
error ErrorCase();
error MessageNotFailed(bytes32 messageId);
enum ErrorCode {
RESOLVED,
FAILED
}
struct FailedMessage {
bytes32 messageId;
ErrorCode errorCode;
}
struct FailedMessagesUsers {
address token;
address receiver;
uint256 amount;
bool isRedeemed;
bytes32 messageId;
}
struct AddressNumber {
address user;
uint256 index;
}
event MessageSent(
bytes32 indexed messageId,
uint64 indexed destinationChainSelector,
address receiver,
string text,
address token,
uint256 tokenAmount,
address feeToken,
uint256 fees
);
event MessageReceived(
bytes32 indexed messageId,
uint64 indexed sourceChainSelector,
address sender,
string text,
address token,
uint256 tokenAmount
);
event MessageFailed(bytes32 indexed messageId, bytes reason);
event MessageRecovered(bytes32 indexed messageId);
event TimeLockActivated(uint256 indexed time);
bytes32 private s_lastReceivedMessageId;
address private s_lastReceivedTokenAddress;
uint256 private s_lastReceivedTokenAmount;
string private s_lastReceivedText;
mapping(uint64 => bool) public allowlistedDestinationChains;
mapping(uint64 => bool) public allowlistedSourceChains;
mapping(address => bool) public allowlistedSenders;
IERC20 private immutable s_linkToken;
address public immutable weth;
address public immutable usdc;
mapping(bytes32 messageId => Client.Any2EVMMessage contents) public s_messageContents;
mapping (address => FailedMessagesUsers[]) public failedMessagesUsers;
mapping (bytes32 => AddressNumber) public failedMessageByMessageId;
EnumerableMap.Bytes32ToUintMap internal s_failedMessages;
IV3SwapRouter public v3Router;
IUniswapV2Router02 public v2Router;
uint256 public swapFee;
address public feeReceiver;
uint256 public constant maxFee = 20000;
uint256 public constant feeBps = 1000;
uint256 public timeLockTime;
constructor(
address _router,
address _link,
address _usdc,
address _v3Router,
address _v2Router,
uint256 _swapFee,
address _feeReceiver
) CCIPReceiver(_router) Ownable(msg.sender) {
s_linkToken = IERC20(_link);
v3Router = IV3SwapRouter(_v3Router);
v2Router = IUniswapV2Router02(_v2Router);
usdc = _usdc;
weth = v3Router.WETH9();
swapFee = _swapFee;
feeReceiver = _feeReceiver;
}
modifier onlyAllowlistedDestinationChain(uint64 _destinationChainSelector) {
if (!allowlistedDestinationChains[_destinationChainSelector])
revert DestinationChainNotAllowlisted(_destinationChainSelector);
_;
}
modifier onlyAllowlisted(uint64 _sourceChainSelector, address _sender) {
if (!allowlistedSourceChains[_sourceChainSelector])
revert SourceChainNotAllowed(_sourceChainSelector);
if (!allowlistedSenders[_sender]) revert SenderNotAllowed(_sender);
_;
}
modifier validateReceiver(address _receiver) {
if (_receiver == address(0)) revert InvalidReceiverAddress();
_;
}
modifier onlySelf() {
if (msg.sender != address(this)) revert OnlySelf();
_;
}
function activateTimelock() external onlyOwner {
timeLockTime = block.timestamp + 48 hours;
emit TimeLockActivated(timeLockTime);
}
function transferOwnership(address newOwner) public override onlyOwner {
require(timeLockTime > 0 && block.timestamp > timeLockTime, "Timelocked");
timeLockTime = 0;
transferOwnership(newOwner);
}
function changeFeeAndAddress(uint256 _fee, address _feeReceiver) external onlyOwner {
require(timeLockTime > 0 && block.timestamp > timeLockTime, "Timelocked");
timeLockTime = 0;
require(_fee < maxFee, "Max fee exceeded");
swapFee = _fee;
feeReceiver = _feeReceiver;
}
function changeRouters(address _v2Router, address _v3Router) external onlyOwner {
require(timeLockTime > 0 && block.timestamp > timeLockTime, "Timelocked");
timeLockTime = 0;
v3Router = IV3SwapRouter(_v3Router);
v2Router = IUniswapV2Router02(_v2Router);
}
function allowlistDestinationChain(
uint64 _destinationChainSelector,
bool allowed
) external onlyOwner {
allowlistedDestinationChains[_destinationChainSelector] = allowed;
}
function allowlistSourceChain(
uint64 _sourceChainSelector,
bool allowed
) external onlyOwner {
allowlistedSourceChains[_sourceChainSelector] = allowed;
}
function allowlistSender(address _sender, bool allowed) external onlyOwner {
allowlistedSenders[_sender] = allowed;
}
function sendMessagePayLINK(
uint64 _destinationChainSelector,
address _receiver,
string memory _text,
address _token,
uint256 _amount,
uint256 _gasLimitReceiver
)
internal
onlyAllowlistedDestinationChain(_destinationChainSelector)
validateReceiver(_receiver)
returns (bytes32 messageId)
{
Client.EVM2AnyMessage memory evm2AnyMessage = _buildCCIPMessage(
_receiver,
_text,
_token,
_amount,
address(s_linkToken),
_gasLimitReceiver
);
IRouterClient router = IRouterClient(this.getRouter());
uint256 fees = router.getFee(_destinationChainSelector, evm2AnyMessage);
if (fees > s_linkToken.balanceOf(address(this)))
revert NotEnoughBalance(s_linkToken.balanceOf(address(this)), fees);
s_linkToken.approve(address(router), fees);
checkAndApproveAll(_token, address(router), _amount);
messageId = router.ccipSend(_destinationChainSelector, evm2AnyMessage);
emit MessageSent(
messageId,
_destinationChainSelector,
_receiver,
_text,
_token,
_amount,
address(s_linkToken),
fees
);
return messageId;
}
function sendMessagePayNative(
uint64 _destinationChainSelector,
address _receiver,
string memory _text,
address _token,
uint256 _amount,
uint256 _gasLimitReceiver
)
internal
onlyAllowlistedDestinationChain(_destinationChainSelector)
validateReceiver(_receiver)
returns (bytes32 messageId)
{
Client.EVM2AnyMessage memory evm2AnyMessage = _buildCCIPMessage(
_receiver,
_text,
_token,
_amount,
address(0),
_gasLimitReceiver
);
IRouterClient router = IRouterClient(this.getRouter());
uint256 fees = router.getFee(_destinationChainSelector, evm2AnyMessage);
if (fees > address(this).balance)
revert NotEnoughBalance(address(this).balance, fees);
checkAndApproveAll(_token, address(router), _amount);
messageId = router.ccipSend{value: fees}(
_destinationChainSelector,
evm2AnyMessage
);
payable(msg.sender).transfer(address(this).balance);
emit MessageSent(
messageId,
_destinationChainSelector,
_receiver,
_text,
_token,
_amount,
address(0),
fees
);
return messageId;
}
struct ReceiverSwapData {
address finalToken;
address userReceiver;
uint256 minAmountOut;
uint256 minAmountOutV2Swap;
bool isV2;
bool unwrapETH;
bytes path;
address[] v2Path;
}
struct InitialSwapData {
address tokenIn;
uint256 amountIn;
uint256 minAmountOutV2Swap;
uint256 minAmountOutV3Swap;
bool swapTokenInV2First;
bool unwrappedETH;
bytes v3InitialSwap;
}
function getLastAddressPath(bytes memory _path) public pure returns(address) {
return _path.toAddress(_path.length - 20);
}
function checkAndApproveAll(address _token, address _target, uint256 _amountToCheck) internal {
if (IERC20(_token).allowance(address(this), _target) < _amountToCheck) {
IERC20(_token).safeApprove(_target, 0);
IERC20(_token).safeApprove(_target, ~uint256(0));
}
}
function swapInitialData(
InitialSwapData memory _initialSwapData
) internal returns(uint256 USDCOut) {
if (_initialSwapData.tokenIn == usdc) {
USDCOut = _initialSwapData.amountIn;
} else {
if (_initialSwapData.swapTokenInV2First) {
require(_initialSwapData.tokenIn != weth, "Token in must not be WETH");
checkAndApproveAll(_initialSwapData.tokenIn, address(v2Router), _initialSwapData.amountIn);
address[] memory path = new address[](2);
path[0] = _initialSwapData.tokenIn;
path[1] = weth;
uint256 wethBalanceBefore = IERC20(weth).balanceOf(address(this));
v2Router.swapExactTokensForTokensSupportingFeeOnTransferTokens(
_initialSwapData.amountIn,
_initialSwapData.minAmountOutV2Swap,
path,
address(this),
block.timestamp
);
uint256 wethBalanceAfter = IERC20(weth).balanceOf(address(this));
uint256 wethOut = wethBalanceAfter - wethBalanceBefore;
_initialSwapData.amountIn = wethOut;
checkAndApproveAll(weth, address(v3Router), wethOut);
} else {
checkAndApproveAll(_initialSwapData.tokenIn, address(v3Router), _initialSwapData.amountIn);
}
uint256 beforeSendingUsdc = IERC20(usdc).balanceOf(address(this));
IV3SwapRouter.ExactInputParams memory params = IV3SwapRouter.ExactInputParams(
_initialSwapData.v3InitialSwap, address(this), _initialSwapData.amountIn, _initialSwapData.minAmountOutV3Swap
);
USDCOut = v3Router.exactInput( params );
uint256 afterSendingUsdc = IERC20(usdc).balanceOf(address(this));
require(afterSendingUsdc > beforeSendingUsdc, "Must swap into USDC");
}
uint256 feeAmount = USDCOut * swapFee / (feeBps * 100);
IERC20(usdc).safeTransfer(feeReceiver, feeAmount);
USDCOut = USDCOut - feeAmount;
}
function sendMessagePayFirstStep(
uint64 _destinationChainSelector,
address _receiverCCIPInOtherChain,
uint256 _gasLimitReceiver,
bool _isLinkOrNative,
InitialSwapData memory _initialSwapData,
ReceiverSwapData memory _receiverSwapData
)
external
payable
onlyAllowlistedDestinationChain(_destinationChainSelector)
validateReceiver(_receiverCCIPInOtherChain)
returns (bytes32 messageId)
{
require(allowlistedSenders[_receiverCCIPInOtherChain], "Must be a valid destination address");
if (!_initialSwapData.unwrappedETH && _initialSwapData.tokenIn == weth) {
IWETH(weth).deposit{value: msg.value - _initialSwapData.amountIn}();
_initialSwapData.amountIn = msg.value - _initialSwapData.amountIn;
} else {
uint256 beforeSending = IERC20(_initialSwapData.tokenIn).balanceOf(address(this));
IERC20(_initialSwapData.tokenIn).safeTransferFrom(msg.sender, address(this), _initialSwapData.amountIn);
uint256 afterSending = IERC20(_initialSwapData.tokenIn).balanceOf(address(this));
_initialSwapData.amountIn = afterSending - beforeSending;
}
address outputToken = getLastAddressPath(_initialSwapData.v3InitialSwap);
require(outputToken == usdc, 'Must swap to USDC');
uint256 USDCOut = swapInitialData(_initialSwapData);
if (_isLinkOrNative) {
return sendMessagePayLINK(
_destinationChainSelector,
_receiverCCIPInOtherChain,
string(abi.encode(
_receiverSwapData
)),
usdc,
USDCOut,
_gasLimitReceiver
);
} else {
return sendMessagePayNative(
_destinationChainSelector,
_receiverCCIPInOtherChain,
string(abi.encode(
_receiverSwapData
)),
usdc,
USDCOut,
_gasLimitReceiver
);
}
}
function calculateFeeGas(
uint64 _destinationChainSelector,
address _receiver,
address _token,
uint256 _amount,
uint256 _gasLimitReceiver,
bool _payInLINK,
ReceiverSwapData memory _receiverSwapData
) external view returns (uint256 fees) {
Client.EVM2AnyMessage memory evm2AnyMessage = _buildCCIPMessage(
_receiver,
string(abi.encode(_receiverSwapData)),
_token,
_amount,
_payInLINK ? address(s_linkToken) : address(0),
_gasLimitReceiver
);
IRouterClient router = IRouterClient(this.getRouter());
fees = router.getFee(_destinationChainSelector, evm2AnyMessage);
}
function getLastReceivedMessageDetails()
public
view
returns (
bytes32 messageId,
string memory text,
address tokenAddress,
uint256 tokenAmount
)
{
return (
s_lastReceivedMessageId,
s_lastReceivedText,
s_lastReceivedTokenAddress,
s_lastReceivedTokenAmount
);
}
function getFailedMessages(
uint256 offset,
uint256 limit
) external view returns (FailedMessage[] memory) {
uint256 length = s_failedMessages.length();
uint256 returnLength = (offset + limit > length)
? length - offset
: limit;
FailedMessage[] memory failedMessages = new FailedMessage[](
returnLength
);
for (uint256 i = 0; i < returnLength; i++) {
(bytes32 messageId, uint256 errorCode) = s_failedMessages.at(
offset + i
);
failedMessages[i] = FailedMessage(messageId, ErrorCode(errorCode));
}
return failedMessages;
}
function ccipReceive(
Client.Any2EVMMessage calldata any2EvmMessage
)
external
override
onlyRouter
onlyAllowlisted(
any2EvmMessage.sourceChainSelector,
abi.decode(any2EvmMessage.sender, (address))
)
{
try this.processMessage(any2EvmMessage) {
} catch (bytes memory err) {
s_failedMessages.set(
any2EvmMessage.messageId,
uint256(ErrorCode.FAILED)
);
s_messageContents[any2EvmMessage.messageId] = any2EvmMessage;
string memory text = abi.decode(any2EvmMessage.data, (string));
ReceiverSwapData memory receiverData = abi.decode(bytes(text), (ReceiverSwapData));
failedMessagesUsers[receiverData.userReceiver].push(FailedMessagesUsers(
usdc,
receiverData.userReceiver,
any2EvmMessage.destTokenAmounts[0].amount,
false,
any2EvmMessage.messageId
));
failedMessageByMessageId[any2EvmMessage.messageId] = AddressNumber(
receiverData.userReceiver, failedMessagesUsers[receiverData.userReceiver].length);
emit MessageFailed(any2EvmMessage.messageId, err);
return;
}
}
function processMessage(
Client.Any2EVMMessage calldata any2EvmMessage
)
external
onlySelf
{
_ccipReceive(any2EvmMessage);
}
function retryFailedMessage(
bytes32 messageId,
address tokenReceiver,
uint256 index
) external onlyOwner {
if (s_failedMessages.get(messageId) != uint256(ErrorCode.FAILED))
revert MessageNotFailed(messageId);
s_failedMessages.set(messageId, uint256(ErrorCode.RESOLVED));
require(failedMessagesUsers[tokenReceiver][index].isRedeemed == false,
"Already redeemed");
failedMessagesUsers[tokenReceiver][index].isRedeemed = true;
Client.Any2EVMMessage storage message = s_messageContents[messageId];
IERC20(message.destTokenAmounts[0].token).safeTransfer(
tokenReceiver,
message.destTokenAmounts[0].amount
);
emit MessageRecovered(messageId);
}
function _ccipReceive(
Client.Any2EVMMessage memory any2EvmMessage
) internal override {
s_lastReceivedMessageId = any2EvmMessage.messageId;
s_lastReceivedText = abi.decode(any2EvmMessage.data, (string));
s_lastReceivedTokenAddress = any2EvmMessage.destTokenAmounts[0].token;
s_lastReceivedTokenAmount = any2EvmMessage.destTokenAmounts[0].amount;
emit MessageReceived(
any2EvmMessage.messageId,
any2EvmMessage.sourceChainSelector,
abi.decode(any2EvmMessage.sender, (address)),
abi.decode(any2EvmMessage.data, (string)),
any2EvmMessage.destTokenAmounts[0].token,
any2EvmMessage.destTokenAmounts[0].amount
);
ReceiverSwapData memory receiverData = abi.decode(bytes(s_lastReceivedText), (ReceiverSwapData));
if (receiverData.finalToken == usdc) {
return IERC20(usdc).safeTransfer(receiverData.userReceiver, s_lastReceivedTokenAmount);
}
IERC20(usdc).approve(address(v3Router), s_lastReceivedTokenAmount);
IV3SwapRouter.ExactInputParams memory params = IV3SwapRouter.ExactInputParams(
receiverData.path,
receiverData.isV2 || receiverData.unwrapETH ? address(this) : receiverData.userReceiver,
s_lastReceivedTokenAmount, receiverData.minAmountOut
);
uint256 wethOrFinalTokenOut = v3Router.exactInput(params);
if (receiverData.isV2) {
IERC20(weth).approve(address(v2Router), wethOrFinalTokenOut);
v2Router.swapExactTokensForTokensSupportingFeeOnTransferTokens(
wethOrFinalTokenOut,
receiverData.minAmountOutV2Swap,
receiverData.v2Path,
receiverData.unwrapETH ? address(this) : receiverData.userReceiver,
block.timestamp
);
}
if (receiverData.unwrapETH) {
uint256 wethBalance = IERC20(weth).balanceOf(address(this));
IWETH(weth).withdraw(wethBalance);
payable(receiverData.userReceiver).transfer(address(this).balance);
}
}
function _buildCCIPMessage(
address _receiver,
string memory _text,
address _token,
uint256 _amount,
address _feeTokenAddress,
uint256 _gasLimitReceiver
) internal pure returns (Client.EVM2AnyMessage memory) {
Client.EVMTokenAmount[]
memory tokenAmounts = new Client.EVMTokenAmount[](1);
Client.EVMTokenAmount memory tokenAmount = Client.EVMTokenAmount({
token: _token,
amount: _amount
});
tokenAmounts[0] = tokenAmount;
Client.EVM2AnyMessage memory evm2AnyMessage = Client.EVM2AnyMessage({
receiver: abi.encode(_receiver),
data: abi.encode(_text),
tokenAmounts: tokenAmounts,
extraArgs: Client._argsToBytes(
Client.EVMExtraArgsV1({gasLimit: _gasLimitReceiver})
),
feeToken: _feeTokenAddress
});
return evm2AnyMessage;
}
receive() external payable {}
function withdraw(address _beneficiary) public onlyOwner {
require(timeLockTime > 0 && block.timestamp > timeLockTime, "Timelocked");
timeLockTime = 0;
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 {
require(timeLockTime > 0 && block.timestamp > timeLockTime, "Timelocked");
timeLockTime = block.timestamp;
uint256 amount = IERC20(_token).balanceOf(address(this));
if (amount == 0) revert NothingToWithdraw();
IERC20(_token).safeTransfer(_beneficiary, amount);
}
function recoverFailedTransfer(
address tokenReceiver,
uint256 index
) external {
FailedMessagesUsers storage f = failedMessagesUsers[tokenReceiver][index];
require(f.isRedeemed == false, "Already redeemed");
f.isRedeemed = true;
require(msg.sender == f.receiver, "Must be executed by the receiver");
if (s_failedMessages.get(f.messageId) != uint256(ErrorCode.FAILED))
revert MessageNotFailed(f.messageId);
s_failedMessages.set(f.messageId, uint256(ErrorCode.RESOLVED));
IERC20(f.token).safeTransfer(
tokenReceiver,
f.amount
);
emit MessageRecovered(f.messageId);
}
function getFailedMessagesUser(
address _user,
uint256 _offset,
uint256 _limit
) external view returns (FailedMessagesUsers[] memory) {
FailedMessagesUsers[] memory results = new FailedMessagesUsers[](_limit);
for (uint256 i = 0; i < _limit; i++) {
results[i] = failedMessagesUsers[_user][_offset+i];
}
return results;
}
function getLengthFailedMessagesUser(address _user) external view returns (uint256) {
uint256 size = failedMessagesUsers[_user].length;
return size;
}
function getFailedMessageByMessageId(bytes32 _messageId) external view returns (FailedMessagesUsers memory) {
AddressNumber storage an = failedMessageByMessageId[_messageId];
return failedMessagesUsers[an.user][an.index];
}
}
文件 4 的 12: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);
}
}
文件 5 的 12: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));
}
}
文件 6 的 12: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;
}
}
文件 7 的 12:IAny2EVMMessageReceiver.sol
pragma solidity ^0.8.0;
import {Client} from "../libraries/Client.sol";
interface IAny2EVMMessageReceiver {
function ccipReceive(Client.Any2EVMMessage calldata message) external;
}
文件 8 的 12:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 9 的 12: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);
}
文件 10 的 12: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 的 12: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");
}
}
}
文件 12 的 12: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": {
"CCIP_NEW.sol": "CCIP"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_router","type":"address"},{"internalType":"address","name":"_link","type":"address"},{"internalType":"address","name":"_usdc","type":"address"},{"internalType":"address","name":"_v3Router","type":"address"},{"internalType":"address","name":"_v2Router","type":"address"},{"internalType":"uint256","name":"_swapFee","type":"uint256"},{"internalType":"address","name":"_feeReceiver","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint64","name":"destinationChainSelector","type":"uint64"}],"name":"DestinationChainNotAllowlisted","type":"error"},{"inputs":[],"name":"ErrorCase","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"FailedToWithdrawEth","type":"error"},{"inputs":[],"name":"InvalidReceiverAddress","type":"error"},{"inputs":[{"internalType":"address","name":"router","type":"address"}],"name":"InvalidRouter","type":"error"},{"inputs":[{"internalType":"bytes32","name":"messageId","type":"bytes32"}],"name":"MessageNotFailed","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":[],"name":"OnlySelf","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"SenderNotAllowed","type":"error"},{"inputs":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"}],"name":"SourceChainNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"messageId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"reason","type":"bytes"}],"name":"MessageFailed","type":"event"},{"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":"string","name":"text","type":"string"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"MessageReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"messageId","type":"bytes32"}],"name":"MessageRecovered","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":"string","name":"text","type":"string"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","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":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"time","type":"uint256"}],"name":"TimeLockActivated","type":"event"},{"inputs":[],"name":"activateTimelock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_destinationChainSelector","type":"uint64"},{"internalType":"bool","name":"allowed","type":"bool"}],"name":"allowlistDestinationChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"bool","name":"allowed","type":"bool"}],"name":"allowlistSender","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_sourceChainSelector","type":"uint64"},{"internalType":"bool","name":"allowed","type":"bool"}],"name":"allowlistSourceChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"}],"name":"allowlistedDestinationChains","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"allowlistedSenders","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"}],"name":"allowlistedSourceChains","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"_destinationChainSelector","type":"uint64"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_gasLimitReceiver","type":"uint256"},{"internalType":"bool","name":"_payInLINK","type":"bool"},{"components":[{"internalType":"address","name":"finalToken","type":"address"},{"internalType":"address","name":"userReceiver","type":"address"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"uint256","name":"minAmountOutV2Swap","type":"uint256"},{"internalType":"bool","name":"isV2","type":"bool"},{"internalType":"bool","name":"unwrapETH","type":"bool"},{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"address[]","name":"v2Path","type":"address[]"}],"internalType":"struct CCIP.ReceiverSwapData","name":"_receiverSwapData","type":"tuple"}],"name":"calculateFeeGas","outputs":[{"internalType":"uint256","name":"fees","type":"uint256"}],"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":"any2EvmMessage","type":"tuple"}],"name":"ccipReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"address","name":"_feeReceiver","type":"address"}],"name":"changeFeeAndAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_v2Router","type":"address"},{"internalType":"address","name":"_v3Router","type":"address"}],"name":"changeRouters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"failedMessageByMessageId","outputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"failedMessagesUsers","outputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"isRedeemed","type":"bool"},{"internalType":"bytes32","name":"messageId","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeReceiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_messageId","type":"bytes32"}],"name":"getFailedMessageByMessageId","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"isRedeemed","type":"bool"},{"internalType":"bytes32","name":"messageId","type":"bytes32"}],"internalType":"struct CCIP.FailedMessagesUsers","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"getFailedMessages","outputs":[{"components":[{"internalType":"bytes32","name":"messageId","type":"bytes32"},{"internalType":"enum CCIP.ErrorCode","name":"errorCode","type":"uint8"}],"internalType":"struct CCIP.FailedMessage[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_offset","type":"uint256"},{"internalType":"uint256","name":"_limit","type":"uint256"}],"name":"getFailedMessagesUser","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"isRedeemed","type":"bool"},{"internalType":"bytes32","name":"messageId","type":"bytes32"}],"internalType":"struct CCIP.FailedMessagesUsers[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_path","type":"bytes"}],"name":"getLastAddressPath","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getLastReceivedMessageDetails","outputs":[{"internalType":"bytes32","name":"messageId","type":"bytes32"},{"internalType":"string","name":"text","type":"string"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getLengthFailedMessagesUser","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRouter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","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":"any2EvmMessage","type":"tuple"}],"name":"processMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenReceiver","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"recoverFailedTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"messageId","type":"bytes32"},{"internalType":"address","name":"tokenReceiver","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"retryFailedMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"messageId","type":"bytes32"}],"name":"s_messageContents","outputs":[{"internalType":"bytes32","name":"messageId","type":"bytes32"},{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"bytes","name":"sender","type":"bytes"},{"internalType":"bytes","name":"data","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"_destinationChainSelector","type":"uint64"},{"internalType":"address","name":"_receiverCCIPInOtherChain","type":"address"},{"internalType":"uint256","name":"_gasLimitReceiver","type":"uint256"},{"internalType":"bool","name":"_isLinkOrNative","type":"bool"},{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"minAmountOutV2Swap","type":"uint256"},{"internalType":"uint256","name":"minAmountOutV3Swap","type":"uint256"},{"internalType":"bool","name":"swapTokenInV2First","type":"bool"},{"internalType":"bool","name":"unwrappedETH","type":"bool"},{"internalType":"bytes","name":"v3InitialSwap","type":"bytes"}],"internalType":"struct CCIP.InitialSwapData","name":"_initialSwapData","type":"tuple"},{"components":[{"internalType":"address","name":"finalToken","type":"address"},{"internalType":"address","name":"userReceiver","type":"address"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"uint256","name":"minAmountOutV2Swap","type":"uint256"},{"internalType":"bool","name":"isV2","type":"bool"},{"internalType":"bool","name":"unwrapETH","type":"bool"},{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"address[]","name":"v2Path","type":"address[]"}],"internalType":"struct CCIP.ReceiverSwapData","name":"_receiverSwapData","type":"tuple"}],"name":"sendMessagePayFirstStep","outputs":[{"internalType":"bytes32","name":"messageId","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"swapFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"timeLockTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"usdc","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"v2Router","outputs":[{"internalType":"contract IUniswapV2Router02","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"v3Router","outputs":[{"internalType":"contract IV3SwapRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","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"},{"stateMutability":"payable","type":"receive"}]