Exercise #2: Deposit transferred USDC to Compound V3
Expand the previous exercise
For this exercise, we will need exercise 1 completed. If you haven't done it already, navigate back to Exercise #1: Cross-Chain Transfer USDCand follow steps.
We will use the already deployed TransferUSDC.sol contract to transfer USDC from Avalanche Fuji to Ethereum Sepolia in this example as well.
Step 1) On Ethereum Sepolia, develop & deploy SwapTestnetUSDC smart contract
Many DeFi protocols, including Compound V3 use their own mock ERC20 tokens on testnets, for easier testing purposes. So we will create this simple smart contract that will swap received, actual USDC, to Compound's mock USDC that we can deposit into Compound V3 on Ethereum Sepolia.
Keep in mind, that this extra step is necessary on test networks only! In production, you will just use the one and only USDC token.
Create a new Solidity file by clicking on the "Create new file" button, name it SwapTestnetUSDC.sol and copy the following codebase into it.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {IERC20} from "@chainlink/contracts-ccip/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/token/ERC20/IERC20.sol";
import {SafeERC20} from "@chainlink/contracts-ccip/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/token/ERC20/utils/SafeERC20.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts@4.8.0/security/ReentrancyGuard.sol";
interface IFauceteer {
function drip(address token) external;
}
/**
* 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.
*/
contract SwapTestnetUSDC is ReentrancyGuard {
using SafeERC20 for IERC20;
address private immutable i_usdcToken;
address private immutable i_compoundUsdcToken;
event Swap(address tokenIn, address tokenOut, uint256 amount, address trader);
constructor(address usdcToken, address compoundUsdcToken, address fauceteer) {
i_usdcToken = usdcToken;
i_compoundUsdcToken = compoundUsdcToken;
IFauceteer(fauceteer).drip(compoundUsdcToken);
}
function swap(address tokenIn, address tokenOut, uint256 amount) external nonReentrant {
require(tokenIn == i_usdcToken || tokenIn == i_compoundUsdcToken);
require(tokenOut == i_usdcToken || tokenOut == i_compoundUsdcToken);
IERC20(tokenIn).safeTransferFrom(msg.sender, address(this), amount);
IERC20(tokenOut).transfer(msg.sender, amount);
emit Swap(tokenIn, tokenOut, amount, msg.sender);
}
function getSupportedTokens() external view returns(address usdcToken, address compoundUsdcToken) {
return(i_usdcToken, i_compoundUsdcToken);
}
}Now open up your Metamask wallet and switch to the Ethereum Sepolia network.
Open the SwapTestnetUSDC.sol file.
Navigate to the "Solidity Compiler" tab and click the "Compile SwapTestnetUSDC.sol" button.
Navigate to the "Deploy & run transactions" tab and select the "Injected Provider - Metamask" option from the "Environment" dropdown menu. Make sure that chainId is switched to 11155111 (if not, you may need to refresh the Remix IDE page in your browser).
Under the "Contract" dropdown menu, make sure that the "SwapTestnetUSDC - SwapTestnetUSDC.sol" is selected.
Locate the orange "Deploy" button. Provide:
0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238, as theusdcTokenparameter;0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238, as thecompoundUsdcTokenparameter;0x68793eA49297eB75DFB4610B68e076D2A5c7646C, as thefauceteerparameter.
Click the orange "Deploy"/"Transact" button.
Metamask notification will pop up. Sign the transaction.
Step 2) On Ethereum Sepolia, develop the CrossChainReceiver smart contract
Create a new Solidity file by clicking on the "Create new file" button, name itCrossChainReceiver.sol and paste the following content.
Step 3) On Ethereum Sepolia, deploy the CrossChainReceiver smart contract
Open up your Metamask wallet and make sure you are connected to the Ethereum Sepolia network.
Open the CrossChainReceiver.sol file.
Navigate to the "Solidity Compiler" tab and click the "Compile CrossChainReceiver.sol" button.
Navigate to the "Deploy & run transactions" tab and select the "Injected Provider - Metamask" option from the "Environment" dropdown menu. Make sure that chainId is switched to 11155111 (if not, you may need to refresh the Remix IDE page in your browser).
Under the "Contract" dropdown menu, make sure that the "CrossChainReceiver - CrossChainReceiver.sol" is selected.
Locate the orange "Deploy" button. Provide:
0x0BF3dE8c5D3e8A2B34D2BEeB17ABfCeBaf363A59, as theccipRouterAddressparameter;0xAec1F48e02Cfb822Be958B68C7957156EB3F0b6e, as thecometAddressparameter;The address of a previously deployed
SwapTestnetUsdc.solsmart contract, as theswapTestnetUsdcAddressparameter.
Click the orange "Deploy"/"Transact" button.
Metamask notification will pop up. Sign the transaction.
Step 4) On Ethereum Sepolia, call allowlistSourceChain function
Under the "Deployed Contracts" section, you should find the CrossChainReceiver.sol contract you previously deployed to Ethereum Sepolia. Find the allowlistSourceChain function and provide:
14767482510784806043, which is the CCIP Chain Selector for the Avalanche Fuji network, as the_sourceChainSelectorparameter.trueas_allowedparameter
Hit the "Transact" orange button.
Step 5) On Ethereum Sepolia, call allowlistSender function
Under the "Deployed Contracts" section, you should find the CrossChainReceiver.sol contract you previously deployed to Ethereum Sepolia. Find the allowlistSender function and provide:
The address of the
TransferUSDC.solsmart contract you deployed in Exercise #1, as the_senderparametertrueas_allowedparameter
Hit the "Transact" orange button.
Step 6) On Avalanche Fuji, call approve function on USDC.sol
Go to the Avalanche Fuji Snowtrace Explorer and search for USDC token. Locate the "Contract" tab, then click the "Write as Proxy" tab. Connect your wallet to the blockchain explorer. And finally find the "approve" function.
We want to approve 1 USDC to be spent by the TransferUSDC.sol on our behalf. To do so we must provide:
The address of the
TransferUSDC.solsmart contract we previously deployed, asspenderparameter1000000, as
valueparameter.

Because USDC token has 6 decimals, 1000000 means that we will approve 1 USDC to be spent on our behalf.
Click the "Write" button. Metamask popup will show up. Sign the transaction.

Step 7) On AvalancheFuji, call transferUsdc function
Under the "Deployed Contracts" section, you should find the TransferUSDC.sol contract you previously deployed to Avalanche Fuji. Find the transferUsdc function and provide:
16015286601757825753, which is the CCIP Chain Selector for the Ethereum Sepolia test network, as the_destinationChainSelectorparameter,The address of a
CrossChainReceiver.solsmart contract you previously deployed to Ethereum Sepolia, as the_receiverparameter,1000000, as the_amountparameter500000, as the_gasLimitparameter
Now we are setting the _gasLimit parameter because we are sending tokens to a smart contract so there is a cost for executing the ccipReceive function on the destination side. In the bonus section of this Masterclass we are going to learn how to actually calculate that exact value. For now, we are setting 500000 gas.
Hit the "Transact" orange button.
You can now monitor the live status of your cross-chain message by copying the transaction hash into the search bar of a Chainlink CCIP Explorer.

Once you receive a cross-chain message, the CrossChainReceiver.sol smart contract will swap received USDC tokens for Compound's mock USDC tokens, deposit those mock tokens into the Compound V3 by calling the Comet.sol smart contract's supply function and CrossChainReceiver.sol smart contract should get COMP tokens in return, which we can see on the Etherscan Blockchain Explorer.
Last updated