runme | ||||
---|---|---|---|---|
|
This repository represents an example of using a Chainlink product or service. It is provided to help you understand how to interact with Chainlink’s systems so that you can integrate them into your own. This template is provided "AS IS" without warranties of any kind, has not been audited, and may be missing key checks or error handling to make the usage of the product more clear. Take everything in this repository as an example and not something to be copy pasted into a production ready service.
Demonstrating how to use Chainlink Cross-Chain Interoperobility Protocol (CCIP) and Avalanche Interchain Messaging (ICM) to send a message from Ethereum Sepolia to Avalanche Fuji (via CCIP), then forwarding that message from Avalanche Fuji to Dispatch L1 (via ICM).
In the next section you can see how to send data from one chain to another. But before that, you need to set up some environment variables, install dependencies, setup environment variables, and compile contracts.
yarn && make
Run the command below, then update the .env PRIVATE_KEY
and ETHERSCAN_API_KEY
variables.
if [ -f .env ]; then
echo "We will use the .env your have already created."
else
if [ -z "${DOTENV}" ]; then
echo "Creating and setting .env"
cp .env.example .env && source .env
echo "Set your PRIVATE_KEY and ETHERSCAN_API_KEY in .env"
fi
fi
To create a new wallet that is stored in a keystore, issue the following command, which will prompt you to secure the private key with a password.
# Grabs the PRIVATE_KEY from the .env file.
PRIVATE_KEY=$(grep PRIVATE_KEY .env | cut -d '=' -f2)
if [ -f keystore/secret ]; then
echo "Found keystore in workspace"
else
if [ -z "${DOTENV}" ]; then
echo "Creating and setting keystore"
mkdir keystore
cast wallet import --private-key $PRIVATE_KEY -k keystore secret
echo "keystore/secret created"
fi
fi
For ease use of the keystore we already configured a environment variable called KEYSTORE
pointing to the keystore
file in the working directory.
You can use the wallet stored in the keystore by adding the --keystore
flag instead of the --private-key
flag. Run the command below to confirm your wallet address is stored accurately.
KEYSTORE=$(grep KEYSTORE .env | cut -d '=' -f2)
cast wallet address --keystore $KEYSTORE
Before we proceed with deployment, it is best practice to run tests, which can be executed as follows:
forge test --match-contract SenderTest -vv
forge test --match-contract BrokerTest -vv
forge test --match-contract ReceiverTest -vv
In order to interact with our contracts, we first need to deploy them, which is simplified in the script/Deploy.s.sol
smart contract, so let's deploy each contract applying the deployment script for each of the following commands.
forge script ./script/Deploy.s.sol:DeploySender -vvv --broadcast --rpc-url ethereumSepolia
Update MESSAGE_SENDER_ADDRESS
stored in your .env, then make sure to verify the deployment by running the following command:
export MESSAGE_SENDER_ADDRESS=$(grep MESSAGE_SENDER_ADDRESS .env | cut -d '=' -f2)
forge verify-contract $MESSAGE_SENDER_ADDRESS src/MessageSender.sol:MessageSender \
--rpc-url 'https://eth-sepolia.public.blastapi.io' \
--verifier blockscout \
--verifier-url 'https://eth-sepolia.blockscout.com/api/'
echo "Verified MessageSender contract may be found here: https://eth-sepolia.blockscout.com/address/$MESSAGE_SENDER_ADDRESS?tab=contract"
Finally, since the MessageSender requires funds to pay for fees, we will load up the contract programatically, as follows with 0.05 ETH:
KEYSTORE=$(grep KEYSTORE .env | cut -d '=' -f2)
cast send $MESSAGE_SENDER_ADDRESS --rpc-url ethereumSepolia --value 0.05ether --keystore $KEYSTORE
forge script ./script/Deploy.s.sol:DeployBroker -vvv --broadcast --rpc-url avalancheFuji
Update MESSAGE_BROKER_ADDRESS
stored in your .env, then make sure to verify the deployment by running the following command:
export MESSAGE_BROKER_ADDRESS=$(grep MESSAGE_BROKER_ADDRESS .env | cut -d '=' -f2)
forge verify-contract $MESSAGE_BROKER_ADDRESS src/MessageBroker.sol:MessageBroker \
--rpc-url 'https://api.avax-test.network/ext/bc/C/rpc' \
--verifier-url 'https://api.routescan.io/v2/network/testnet/evm/43113/etherscan' \
--etherscan-api-key "verifyContract"
echo "Verified MessageBroker contract may be found here: https://testnet.snowtrace.io/address/$MESSAGE_BROKER_ADDRESS/contract/43113/code"
forge script ./script/Deploy.s.sol:DeployReceiver -vvv --broadcast --rpc-url dispatchTestnet
Update MESSAGE_RECEIVER_ADDRESS
stored in your .env, then make sure to verify the deployment by running the following command:
export MESSAGE_RECEIVER_ADDRESS=$(grep MESSAGE_RECEIVER_ADDRESS .env | cut -d '=' -f2)
forge verify-contract $MESSAGE_RECEIVER_ADDRESS src/MessageReceiver.sol:MessageReceiver --etherscan-api-key 'verifyContract' \
&& orge verify-contract $MESSAGE_RECEIVER_ADDRESS src/MessageReceiver.sol:MessageReceiver \
--rpc-url 'https://subnets.avax.network/dispatch/testnet/rpc' \
--verifier-url 'https://api.routescan.io/v2/network/testnet/evm/779672/etherscan' \
echo "Verified MessageReceiver contract may be found here: https://779672.testnet.snowtrace.io/address/$MESSAGE_RECEIVER_ADDRESS/contract/779672/code"
Before proceeding, please ensure you have completed the steps outlined in the Setup Messaging Scenario section above.
Run the following to send a message to Fuji from Sepolia via the SendMessage
functionality coded in Send.s.sol:
export CUSTOM_MESSAGE=""
if [ -z "${CUSTOM_MESSAGE}" ]; then
echo "No custom message provided"
else
echo "Sending \`$CUSTOM_MESSAGE\` to Avalanche"
fi
forge script ./script/Send.s.sol:SendMessage -vvv --broadcast --rpc-url ethereumSepolia --sig "run(string)" -- "$CUSTOM_MESSAGE"
# https://ccip.chain.link/#/side-drawer/msg/0x30917345c2214ca9a26631f24f30e67b0f7d3aef2285c4ec108a124d944886f1
Once the message is finalized on the broker chain (Fuji), you may see the details about the latest message via the BrokerMessage
functionality coded in Broker.s.sol. After you have confirmed the latest message you received looks good, you may proceed with running the following script to broker the message to Dispatch:
MESSAGE_BROKER_ADDRESS=$(grep MESSAGE_BROKER_ADDRESS .env | cut -d '=' -f2)
MESSAGE_RECEIVER_ADDRESS=$(grep MESSAGE_RECEIVER_ADDRESS .env | cut -d '=' -f2)
KEYSTORE=$(grep KEYSTORE .env | cut -d '=' -f2)
cast send $MESSAGE_BROKER_ADDRESS --rpc-url avalancheFuji --keystore $KEYSTORE "brokerMessage(address)" $MESSAGE_RECEIVER_ADDRESS
After running the script above to broker the message from Fuji to Dispatch, you may confirm the message was received by running the following script:
forge script ./script/Receive.s.sol:ReceiveMessage -vvv --broadcast --rpc-url dispatchTestnet