Created
May 10, 2024 02:40
-
-
Save QingyangKong/5c741a47a2cd470a89d755420e2bcac2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity 0.8.19; | |
import {IRouterClient} from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol"; | |
import {OwnerIsCreator} from "@chainlink/contracts-ccip/src/v0.8/shared/access/OwnerIsCreator.sol"; | |
import {Client} from "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol"; | |
import {IERC20} from "@chainlink/contracts-ccip/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; | |
import {SafeERC20} from "@chainlink/contracts-ccip/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; | |
/** | |
* THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. | |
* THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. | |
* DO NOT USE THIS CODE IN PRODUCTION. | |
*/ | |
/// @title - A simple messenger contract for transferring/receiving tokens and data across chains. | |
contract SourceChainSender is OwnerIsCreator { | |
using SafeERC20 for IERC20; | |
address public routerAvaFuji = 0xF694E193200268f9a4868e4Aa017A0118C9a8177; | |
IERC20 public s_linkToken = IERC20(0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846); | |
uint64 public sepoliaChainSelector = 16015286601757825753; | |
// Custom errors to provide more descriptive revert messages. | |
error NotEnoughBalance(uint256 currentBalance, uint256 calculatedFees); // Used to make sure contract has enough balance to cover the fees. | |
error NothingToWithdraw(); // Used when trying to withdraw Ether but there's nothing to withdraw. | |
error FailedToWithdrawEth(address owner, address target, uint256 value); // Used when the withdrawal of Ether fails. | |
/// @notice Sends data and transfer tokens to receiver on the destination chain. | |
/// @notice Pay for fees in LINK. | |
/// @dev Assumes your contract has sufficient LINK to pay for CCIP fees. | |
/// @param _receiver The address of the recipient on the destination blockchain. | |
/// @return messageId The ID of the CCIP message that was sent. | |
function sendMessagePayLINK(address _receiver) | |
external | |
onlyOwner | |
returns (bytes32 messageId) | |
{ | |
bytes memory functionCall = abi.encodeWithSignature("safeMint(address)", msg.sender); | |
Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](0); | |
Client.EVM2AnyMessage memory evm2AnyMessage = Client.EVM2AnyMessage({ | |
receiver: abi.encode(_receiver), // ABI-encoded receiver address | |
data: functionCall, // ABI-encoded string | |
tokenAmounts: tokenAmounts, // The amount and type of token being transferred | |
extraArgs: Client._argsToBytes( | |
// Additional arguments, setting gas limit | |
Client.EVMExtraArgsV1({gasLimit: 200_000}) | |
), | |
// Set the feeToken to a feeTokenAddress, indicating specific asset will be used for fees | |
feeToken: address(s_linkToken) | |
}); | |
// Initialize a router client instance to interact with cross-chain router | |
IRouterClient router = IRouterClient(routerAvaFuji); | |
// Get the fee required to send the CCIP message | |
uint256 fees = router.getFee(sepoliaChainSelector, evm2AnyMessage); | |
if (fees > s_linkToken.balanceOf(address(this))) | |
revert NotEnoughBalance(s_linkToken.balanceOf(address(this)), fees); | |
// approve the Router to spend LINK and token on contract's behalf. | |
s_linkToken.approve(address(router), fees); | |
// Send the message through the router and store the returned message ID | |
messageId = router.ccipSend(sepoliaChainSelector, evm2AnyMessage); | |
// Return the message ID | |
return messageId; | |
} | |
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).safeTransfer(_beneficiary, amount); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment