Skip to content

Instantly share code, notes, and snippets.

@gat786
Created August 30, 2023 17:59
Show Gist options
  • Save gat786/081d3400fe745aa5705d84f1871f16e8 to your computer and use it in GitHub Desktop.
Save gat786/081d3400fe745aa5705d84f1871f16e8 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 {LinkTokenInterface} from "@chainlink/contracts/src/v0.8/interfaces/LinkTokenInterface.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 contract for sending string data across chains.
contract Sender is OwnerIsCreator {
// Custom errors to provide more descriptive revert messages.
error NotEnoughBalance(uint256 currentBalance, uint256 calculatedFees); // Used to make sure contract has enough balance.
// Event emitted when a message is sent to another chain.
event MessageSent(
bytes32 indexed messageId, // The unique ID of the CCIP message.
uint64 indexed destinationChainSelector, // The chain selector of the destination chain.
address receiver, // The address of the receiver on the destination chain.
string text, // The text being sent.
address feeToken, // the token address used to pay CCIP fees.
uint256 fees // The fees paid for sending the CCIP message.
);
IRouterClient router;
LinkTokenInterface linkToken;
/// @notice Constructor initializes the contract with the router address.
/// @param _router The address of the router contract.
/// @param _link The address of the link contract.
constructor(address _router, address _link) {
router = IRouterClient(_router);
linkToken = LinkTokenInterface(_link);
}
/// @notice Sends data to receiver on the destination chain.
/// @dev Assumes your contract has sufficient LINK.
/// @param destinationChainSelector The identifier (aka selector) for the destination blockchain.
/// @param receiver The address of the recipient on the destination blockchain.
/// @param text The string text to be sent.
/// @return messageId The ID of the message that was sent.
function sendMessage(
uint64 destinationChainSelector,
address receiver,
string calldata text
) external onlyOwner returns (bytes32 messageId) {
// Create an EVM2AnyMessage struct in memory with necessary information for sending a cross-chain message
Client.EVM2AnyMessage memory evm2AnyMessage = Client.EVM2AnyMessage({
receiver: abi.encode(receiver), // ABI-encoded receiver address
data: abi.encode(text), // ABI-encoded string
tokenAmounts: new Client.EVMTokenAmount[](0), // Empty array indicating no tokens are being sent
extraArgs: Client._argsToBytes(
// Additional arguments, setting gas limit and non-strict sequencing mode
Client.EVMExtraArgsV1({gasLimit: 200_000, strict: false})
),
// Set the feeToken address, indicating LINK will be used for fees
feeToken: address(linkToken)
});
// Get the fee required to send the message
uint256 fees = router.getFee(destinationChainSelector, evm2AnyMessage);
if (fees > linkToken.balanceOf(address(this)))
revert NotEnoughBalance(linkToken.balanceOf(address(this)), fees);
// approve the Router to transfer LINK tokens on contract's behalf. It will spend the fees in LINK
linkToken.approve(address(router), fees);
// Send the message through the router and store the returned message ID
messageId = router.ccipSend(destinationChainSelector, evm2AnyMessage);
// Emit an event with message details
emit MessageSent(
messageId,
destinationChainSelector,
receiver,
text,
address(linkToken),
fees
);
// Return the message ID
return messageId;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment