Skip to content

Instantly share code, notes, and snippets.

@QingyangKong
Created May 10, 2024 02:40
Show Gist options
  • Save QingyangKong/5c741a47a2cd470a89d755420e2bcac2 to your computer and use it in GitHub Desktop.
Save QingyangKong/5c741a47a2cd470a89d755420e2bcac2 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.
/// @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