Skip to content

Instantly share code, notes, and snippets.

@QingyangKong
Last active May 10, 2024 06:31
Show Gist options
  • Save QingyangKong/393a9c3380c3485947bf5060856d10d2 to your computer and use it in GitHub Desktop.
Save QingyangKong/393a9c3380c3485947bf5060856d10d2 to your computer and use it in GitHub Desktop.
// 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.
/// @param _text The string data to be sent.
/// @param _token token address.
/// @param _amount token amount.
/// @return messageId The ID of the CCIP message that was sent.
function sendMessagePayLINK(
address _receiver,
string calldata _text,
address _token,
uint256 _amount
)
external
onlyOwner
returns (bytes32 messageId)
{
Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
tokenAmounts[0] = Client.EVMTokenAmount({
token: _token,
amount: _amount
});
Client.EVM2AnyMessage memory evm2AnyMessage = Client.EVM2AnyMessage({
receiver: abi.encode(_receiver), // ABI-encoded receiver address
data: abi.encode(_text), // 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);
IERC20(_token).approve(address(router), _amount);
// Send the message through the router and store the returned message ID
messageId = router.ccipSend(sepoliaChainSelector, evm2AnyMessage);
// Return the message ID
return messageId;
}
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